Go API Documentation

github.com/TykTechnologies/tyk/gateway

No package summary is available.

Package

Files: 109. Third party imports: 41. Imports from organisation: 18. Tests: 0. Benchmarks: 0.

Constants

const BackupApiKeyBase = "node-definition-backup:"
const BackupPolicyKeyBase = "node-policy-backup:"
// CoProcessDefaultKeyPrefix is used as a key prefix for this CP.
const CoProcessDefaultKeyPrefix = "coprocess-data:"
// EH_CoProcessHandler is used for event system, maintained here for backwards compatibility.
const EH_CoProcessHandler = event.CoProcessHandler
const JWKsAPIDef = "jwks_api_def_"
const ListDetailed = "detailed"
const LoopScheme = "tyk"
const (
	MessageStreamingOnlySupportedInEE = "streaming is supported only in Tyk Enterprise Edition"
)
const OIDPREFIX = "openid"
const RPCKeyPrefix = "rpc:"
const RestrictedFieldValidationFailedLogMsg = "Error during GraphQL request restricted fields validation: '%s'"
// const used by cache middleware
const SAFE_METHODS = "SAFE_METHODS"
const UnexpectedSigningMethod = "Unexpected signing method"
const XTykAPIExpires = "x-tyk-api-expires"
const (
	// EventQuotaExceeded is an alias maintained for backwards compatibility.
	EventQuotaExceeded	= event.QuotaExceeded
	// RateLimitExceeded is an alias maintained for backwards compatibility.
	EventRateLimitExceeded	= event.RateLimitExceeded
	// EventAuthFailure is an alias maintained for backwards compatibility.
	EventAuthFailure	= event.AuthFailure
	// EventUpstreamOAuthError is an alias maintained for backwards compatibility.
	UpstreamOAuthError	= event.UpstreamOAuthError
	// EventKeyExpired is an alias maintained for backwards compatibility.
	EventKeyExpired	= event.KeyExpired
	// EventVersionFailure is an alias maintained for backwards compatibility.
	EventVersionFailure	= event.VersionFailure
	// EventOrgQuotaExceeded is an alias maintained for backwards compatibility.
	EventOrgQuotaExceeded	= event.OrgQuotaExceeded
	// EventOrgRateLimitExceeded is an alias maintained for backwards compatibility.
	EventOrgRateLimitExceeded	= event.OrgRateLimitExceeded
	// EventTriggerExceeded is an alias maintained for backwards compatibility.
	EventTriggerExceeded	= event.TriggerExceeded
	// EventBreakerTriggered is an alias maintained for backwards compatibility.
	EventBreakerTriggered	= event.BreakerTriggered
	// EventBreakerTripped is an alias maintained for backwards compatibility.
	EventBreakerTripped	= event.BreakerTripped
	// EventBreakerReset is an alias maintained for backwards compatibility.
	EventBreakerReset	= event.BreakerReset
	// EventHOSTDOWN is an alias maintained for backwards compatibility.
	EventHOSTDOWN	= event.HostDown
	// EventHOSTUP is an alias maintained for backwards compatibility.
	EventHOSTUP	= event.HostUp
	// EventTokenCreated is an alias maintained for backwards compatibility.
	EventTokenCreated	= event.TokenCreated
	// EventTokenUpdated is an alias maintained for backwards compatibility.
	EventTokenUpdated	= event.TokenUpdated
	// EventTokenDeleted is an alias maintained for backwards compatibility.
	EventTokenDeleted	= event.TokenDeleted
)
// Statuses of the request, all are false-y except StatusOk and StatusOkAndIgnore
const (
	VersionNotFound			RequestStatus	= "Version information not found"
	VersionDoesNotExist		RequestStatus	= "This API version does not seem to exist"
	VersionWhiteListStatusNotFound	RequestStatus	= "WhiteListStatus for path not found"
	VersionExpired			RequestStatus	= "Api Version has expired, please check documentation or contact administrator"
	APIExpired			RequestStatus	= "API has expired, please check documentation or contact administrator"
	EndPointNotAllowed		RequestStatus	= "Requested endpoint is forbidden"
	StatusOkAndIgnore		RequestStatus	= "Everything OK, passing and not filtering"
	StatusOk			RequestStatus	= "Everything OK, passing"
	StatusCached			RequestStatus	= "Cached path"
	StatusTransform			RequestStatus	= "Transformed path"
	StatusTransformResponse		RequestStatus	= "Transformed response"
	StatusTransformJQ		RequestStatus	= "Transformed path with JQ"
	StatusTransformJQResponse	RequestStatus	= "Transformed response with JQ"
	StatusHeaderInjected		RequestStatus	= "Header injected"
	StatusMethodTransformed		RequestStatus	= "Method Transformed"
	StatusHeaderInjectedResponse	RequestStatus	= "Header injected on response"
	StatusRedirectFlowByReply	RequestStatus	= "Exceptional action requested, redirecting flow!"
	StatusHardTimeout		RequestStatus	= "Hard Timeout enforced on path"
	StatusCircuitBreaker		RequestStatus	= "Circuit breaker enforced"
	StatusURLRewrite		RequestStatus	= "URL Rewritten"
	StatusVirtualPath		RequestStatus	= "Virtual Endpoint"
	StatusRequestSizeControlled	RequestStatus	= "Request Size Limited"
	StatusRequestTracked		RequestStatus	= "Request Tracked"
	StatusRequestNotTracked		RequestStatus	= "Request Not Tracked"
	StatusValidateJSON		RequestStatus	= "Validate JSON"
	StatusValidateRequest		RequestStatus	= "Validate Request"
	StatusInternal			RequestStatus	= "Internal path"
	StatusGoPlugin			RequestStatus	= "Go plugin"
	StatusPersistGraphQL		RequestStatus	= "Persist GraphQL"
	StatusRateLimit			RequestStatus	= "Rate Limited"
)
const (
	recordsBufferFlushInterval		= 200 * time.Millisecond
	recordsBufferForcedFlushInterval	= 1 * time.Second
)
const (
	playgroundJSTemplateName	= "playground.js"
	playgroundHTMLTemplateName	= "index.html"
)
const (
	Throttle		HealthPrefix	= "Throttle"
	QuotaViolation		HealthPrefix	= "QuotaViolation"
	KeyFailure		HealthPrefix	= "KeyFailure"
	RequestLog		HealthPrefix	= "Request"
	BlockedRequestLog	HealthPrefix	= "BlockedRequest"
)
const (
	prefixEnv	= "env://"
	prefixSecrets	= "secrets://"
	prefixConsul	= "consul://"
	prefixVault	= "vault://"
	prefixKeys	= "tyk-apis"
	vaultSecretPath	= "secret/data/"
)
// Constants for heartBeatStopSentinel indicators.
//
// Go 1.17 adds atomic.Value.Swap which is great, but 1.19
// adds atomic.Bool and other types. This is a go <1.13 cludge.
const (
	// HeartBeatStarted Zero value - the handlers started
	HeartBeatStarted	= 0

	// HeartBeatStopped value - the handlers invoked shutdown
	HeartBeatStopped	= 1
)
const (
	WH_GET		WebHookRequestMethod	= "GET"
	WH_PUT		WebHookRequestMethod	= "PUT"
	WH_POST		WebHookRequestMethod	= "POST"
	WH_DELETE	WebHookRequestMethod	= "DELETE"
	WH_PATCH	WebHookRequestMethod	= "PATCH"
)
const (
	// EH_WebHook is an alias maintained for backwards compatibility.
	// it is the handler to register a webhook event.
	EH_WebHook	= event.WebHookHandler
	// EH_JSVMHandler is aliased for backwards compatibility.
	EH_JSVMHandler	= event.JSVMHandler
	// EH_LogHandler is an alias maintained for backwards compatibility.
	// It is used to register log handler on an event.
	EH_LogHandler	= event.LogHandler
)
// Notification codes for new and refresh codes
const (
	newAccessToken		OAuthNotificationType	= "new"
	refreshAccessToken	OAuthNotificationType	= "refresh"
)
const (
	defaultTemplateName	= "error"
	defaultTemplateFormat	= "json"
	defaultContentType	= header.ApplicationJSON

	MsgAuthFieldMissing				= "Authorization field missing"
	MsgApiAccessDisallowed				= "Access to this API has been disallowed"
	MsgBearerMailformed				= "Bearer token malformed"
	MsgKeyNotAuthorized				= "Key not authorised"
	MsgOauthClientRevoked				= "Key not authorised. OAuth client access was revoked"
	MsgKeyNotAuthorizedUnexpectedSigningMethod	= "Key not authorized: Unexpected signing method"
	MsgCertificateExpired				= "Certificate has expired"
)
const (
	keyDataDeveloperID	= "tyk_developer_id"
	keyDataDeveloperEmail	= "tyk_developer_email"
)
const (
	Pass		= model.Pass
	Fail		= model.Fail
	Warn		= model.Warn
	Datastore	= model.Datastore
	System		= model.System
)
const (
	defaultTimeout			= 10
	defaultSampletTriggerLimit	= 3
)
const (
	// Zero value - the service is open and ready to use
	OPEN	= 0

	// Closed value - the service shouldn't be used
	CLOSED	= 1
)
const (
	UnHealthyHostMetaDataTargetKey	= "target_url"
	UnHealthyHostMetaDataAPIKey	= "api_id"
	UnHealthyHostMetaDataHostKey	= "host_name"
	PollerCacheKey			= "PollerActiveInstanceID"
	PoolerHostSentinelKeyPrefix	= "PollerCheckerInstance:"

	UptimeAnalytics_KEYNAME	= "tyk-uptime-analytics"
)
const (
	statsdCmdKindEvent	statsdCmdKind	= iota
	statsdCmdKindEventErr
	statsdCmdKindTiming
	statsdCmdKindGauge
	statsdCmdKindComplete
	statsdCmdKindFlush
	statsdCmdKindDrain
	statsdCmdKindStop
)
const (
	handlerPathGraphQLProxyUpstream		= "/graphql-proxy-upstream"
	handlerPathGraphQLProxyUpstreamError	= "/graphql-proxy-upstream-error"
	handlerPathRestDataSource		= "/rest-data-source"
	handlerPathRestDataSourceV3		= "/rest-data-source-v2"
	handlerPathGraphQLDataSource		= "/graphql-data-source"
	handlerPathHeadersRestDataSource	= "/rest-headers-data-source"
	handlerSubgraphAccounts			= "/subgraph-accounts"
	handlerSubgraphAccountsModified		= "/subgraph-accounts-modified"
	handlerSubgraphReviews			= "/subgraph-reviews"

	// We need a static port so that the urls can be used in static
	// test data, and to prevent the requests from being randomized
	// for checksums. Port 16500 should be obscure and unused.
	testHttpListen	= "127.0.0.1:16500"
	// Accepts any http requests on /, only allows GET on /get, etc.
	// All return a JSON with request info.
	TestHttpAny			= "http://" + testHttpListen
	TestHttpGet			= TestHttpAny + "/get"
	testHttpPost			= TestHttpAny + "/post"
	testGraphQLProxyUpstream	= TestHttpAny + handlerPathGraphQLProxyUpstream
	testGraphQLProxyUpstreamError	= TestHttpAny + handlerPathGraphQLProxyUpstreamError
	testGraphQLDataSource		= TestHttpAny + handlerPathGraphQLDataSource
	testRESTDataSource		= TestHttpAny + handlerPathRestDataSource
	testRESTDataSourceV3		= TestHttpAny + handlerPathRestDataSourceV3
	testRESTHeadersDataSource	= TestHttpAny + handlerPathHeadersRestDataSource
	testSubgraphAccounts		= TestHttpAny + handlerSubgraphAccounts
	testSubgraphAccountsModified	= TestHttpAny + handlerSubgraphAccountsModified
	testSubgraphReviews		= TestHttpAny + handlerSubgraphReviews
	testHttpJWK			= TestHttpAny + "/jwk.json"
	testHttpJWKLegacy		= TestHttpAny + "/jwk-legacy.json"
	testHttpBundles			= TestHttpAny + "/bundles/"
	testReloadGroup			= TestHttpAny + "/groupReload"

	// Nothing should be listening on port 16501 - useful for
	// testing TCP and HTTP failures.
	testHttpFailure		= "127.0.0.1:16501"
	testHttpFailureAny	= "http://" + testHttpFailure
	MockOrgID		= "507f1f77bcf86cd799439011"
	NonCanonicalHeaderKey	= "X-CertificateOuid"
)
const (
	sessionFailNone	sessionFailReason	= iota
	sessionFailRateLimit
	sessionFailQuota
	sessionFailInternalServerError
)
const (
	// QuotaKeyPrefix serves as a standard prefix for generating quota keys.
	QuotaKeyPrefix	= "quota-"

	// RateLimitKeyPrefix serves as a standard prefix for generating rate limiter keys.
	RateLimitKeyPrefix	= rate.LimiterKeyPrefix

	// SentinelRateLimitKeyPostfix is appended to the rate limiting key to combine into a sentinel key.
	SentinelRateLimitKeyPostfix	= ".BLOCKED"
)
const (
	accessToken	= "access_token"
	refreshToken	= "refresh_token"
)
const (
	ErrOAuthAuthorizationFieldMissing	= "oauth.auth_field_missing"
	ErrOAuthAuthorizationFieldMalformed	= "oauth.auth_field_malformed"
	ErrOAuthKeyNotFound			= "oauth.key_not_found"
	ErrOAuthClientDeleted			= "oauth.client_deleted"
)
const (
	mwStatusRespond			= middleware.StatusRespond
	DEFAULT_ORG_SESSION_EXPIRATION	= int64(604800)
)
// These enums fix the prefix to use when storing various OAuth keys and data, since we
// delegate everything to the osin framework
const (
	prefixAuth		= "oauth-authorize."
	prefixClient		= "oauth-clientid."
	prefixAccess		= "oauth-access."
	prefixRefresh		= "oauth-refresh."
	prefixClientset		= "oauth-clientset."
	prefixClientIndexList	= "oauth-client-index."
	prefixClientTokens	= "oauth-client-tokens."
)
const (
	LDAPStorageEngine	apidef.StorageEngineCode	= "ldap"
	RPCStorageEngine	apidef.StorageEngineCode	= "rpc"
)
// Enums representing the various statuses for a VersionInfo Path match during a
// proxy request
const (
	_	URLStatus	= iota
	Ignored
	WhiteList
	BlackList
	MockResponse
	Cached
	Transformed
	TransformedJQ
	HeaderInjected
	HeaderInjectedResponse
	TransformedResponse
	TransformedJQResponse
	HardTimeout
	CircuitBreaker
	URLRewrite
	VirtualPath
	RequestSizeLimit
	MethodTransformed
	RequestTracked
	RequestNotTracked
	ValidateJSONRequest
	Internal
	GoPlugin
	PersistGraphQL
	RateLimit
)
const (
	defaultSignatureErrorCode	= http.StatusUnauthorized
	defaultSignatureErrorMessage	= "Request signature verification failed"
)
const (
	ErrAuthAuthorizationFieldMissing	= "auth.auth_field_missing"
	ErrAuthKeyNotFound			= "auth.key_not_found"
	ErrAuthCertNotFound			= "auth.cert_not_found"
	ErrAuthCertExpired			= "auth.cert_expired"
	ErrAuthKeyIsInvalid			= "auth.key_is_invalid"

	MsgNonExistentKey	= "Attempted access with non-existent key."
	MsgNonExistentCert	= "Attempted access with non-existent cert."
	MsgInvalidKey		= "Attempted access with invalid key."
)
const (
	ResetQuota		string	= "resetQuota"
	CertificateRemoved	string	= "CertificateRemoved"
	CertificateAdded	string	= "CertificateAdded"
	OAuthRevokeToken	string	= "oAuthRevokeToken"
	OAuthRevokeAccessToken	string	= "oAuthRevokeAccessToken"
	OAuthRevokeRefreshToken	string	= "oAuthRevokeRefreshToken"
	OAuthRevokeAllTokens	string	= "revoke_all_tokens"
	OauthClientAdded	string	= "OauthClientAdded"
	OauthClientRemoved	string	= "OauthClientRemoved"
	OauthClientUpdated	string	= "OauthClientUpdated"
)
const (
	ComplexityFailReasonNone	ComplexityFailReason	= iota
	ComplexityFailReasonInternalError
	ComplexityFailReasonDepthLimitExceeded
)
const (
	GranularAccessFailReasonNone	GranularAccessFailReason	= iota
	GranularAccessFailReasonInternalError
	GranularAccessFailReasonValidationError
)
const (
	metaLabel		= "$tyk_meta."
	contextLabel		= "$tyk_context."
	consulLabel		= "$secret_consul."
	vaultLabel		= "$secret_vault."
	envLabel		= "$secret_env."
	secretsConfLabel	= "$secret_conf."
	triggerKeyPrefix	= "trigger"
	triggerKeySep		= "-"
)
const (
	checkIdleMemConnInterval	= 5 * time.Minute
	maxIdleMemConnDuration		= time.Minute
	inMemNetworkName		= "in-mem-network"
	inMemNetworkType		= "memu"
)
const (
	KID		= "kid"
	SUB		= "sub"
	HMACSign	= "hmac"
	RSASign		= "rsa"
	ECDSASign	= "ecdsa"
)
const (
	upstreamCacheHeader	= "x-tyk-cache-action-set"
	upstreamCacheTTLHeader	= "x-tyk-cache-action-set-ttl"
)
const (
	RedisPubSubChannel	= "tyk.cluster.notifications"

	NoticeApiUpdated		NotificationCommand	= "ApiUpdated"
	NoticeApiRemoved		NotificationCommand	= "ApiRemoved"
	NoticeApiAdded			NotificationCommand	= "ApiAdded"
	NoticeGroupReload		NotificationCommand	= "GroupReload"
	NoticePolicyChanged		NotificationCommand	= "PolicyChanged"
	NoticeConfigUpdate		NotificationCommand	= "NoticeConfigUpdated"
	NoticeDashboardZeroConf		NotificationCommand	= "NoticeDashboardZeroConf"
	NoticeDashboardConfigRequest	NotificationCommand	= "NoticeDashboardConfigRequest"
	NoticeGatewayConfigResponse	NotificationCommand	= "NoticeGatewayConfigResponse"
	NoticeGatewayDRLNotification	NotificationCommand	= "NoticeGatewayDRLNotification"
	KeySpaceUpdateNotification	NotificationCommand	= "KeySpaceUpdateNotification"
	OAuthPurgeLapsedTokens		NotificationCommand	= "OAuthPurgeLapsedTokens"
	// NoticeDeleteAPICache is the command with which event is emitted from dashboard to invalidate cache for an API.
	NoticeDeleteAPICache	NotificationCommand	= "DeleteAPICache"
	NoticeUserKeyReset	NotificationCommand	= "UserKeyReset"
)
const acceptCode = "X-Tyk-Accept-Example-Code"
const acceptContentType = "Accept"
const acceptExampleName = "X-Tyk-Accept-Example-Name"
const altHeaderSpec = "x-aux-date"
const analyticsKeyName = "tyk-system-analytics"
const appName = "tyk-gateway"
const arrayName = "tyk_array"
const (
	cachedResponseHeader = "x-tyk-cached-response"
)
const (
	// Check OAuth client deleted interval in seconds.
	checkOAuthClientDeletedInterval = 1
)
const cmdChanBuffSize = 8192	// random-ass-guess
const coreJS = `
var TykJS = {
	TykMiddleware: {
		MiddlewareComponentMeta: function(configuration) {
			this.configuration = configuration
		}
	},
	TykEventHandlers: {
		EventHandlerComponentMeta: function() {}
	}
}

TykJS.TykMiddleware.MiddlewareComponentMeta.prototype.ProcessRequest = function(request, session, config) {
	log("Process Request Not Implemented")
	return request
}

TykJS.TykMiddleware.MiddlewareComponentMeta.prototype.DoProcessRequest = function(request, session, config) {
	request.Body = b64dec(request.Body)
	var processed_request = this.ProcessRequest(request, session, config)

	if (!processed_request) {
		log("Middleware didn't return request object!")
		return
	}

	// Reset the headers object
	processed_request.Request.Headers = {}
	processed_request.Request.Body = b64enc(processed_request.Request.Body)

	return JSON.stringify(processed_request)
}

// The user-level middleware component
TykJS.TykMiddleware.NewMiddleware = function(configuration) {
	TykJS.TykMiddleware.MiddlewareComponentMeta.call(this, configuration)
}

// Set up object inheritance
TykJS.TykMiddleware.NewMiddleware.prototype = Object.create(TykJS.TykMiddleware.MiddlewareComponentMeta.prototype)
TykJS.TykMiddleware.NewMiddleware.prototype.constructor = TykJS.TykMiddleware.NewMiddleware

TykJS.TykMiddleware.NewMiddleware.prototype.NewProcessRequest = function(callback) {
	this.ProcessRequest = callback
}

TykJS.TykMiddleware.NewMiddleware.prototype.ReturnData = function(request, session) {
	return {Request: request, SessionMeta: session}
}

TykJS.TykMiddleware.NewMiddleware.prototype.ReturnAuthData = function(request, session) {
	return {Request: request, Session: session}
}

// Event Handler implementation

TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype.DoProcessEvent = function(event, context) {
	// call the handler
	log("Calling built - in handle")
	this.Handle(event, context)
	return
}

TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype.Handle = function(request, context) {
	log("Handler not implemented!")
	return request
}

// The user-level event handler component
TykJS.TykEventHandlers.NewEventHandler = function() {
	TykJS.TykEventHandlers.EventHandlerComponentMeta.call(this)
}

// Set up object inheritance for events
TykJS.TykEventHandlers.NewEventHandler.prototype = Object.create(TykJS.TykEventHandlers.EventHandlerComponentMeta.prototype)
TykJS.TykEventHandlers.NewEventHandler.prototype.constructor = TykJS.TykEventHandlers.NewEventHandler

TykJS.TykEventHandlers.NewEventHandler.prototype.NewHandler = function(callback) {
	this.Handle = callback
};`
const dateHeaderSpec = "Date"
const defaultBasicAuthTTL int64 = 60
const defaultJSVMTimeout = 5
// Check for recursion
const defaultLoopLevelLimit = 5
const defaultProxyTimeout float64 = 30
const jsonContentType = "application/json"
const jwkTestJson = `{
    "keys": [
        {
            "use": "sig",
            "kty": "RSA",
            "kid": "12345",
            "alg": "RS256",
            "n": "yqZ4rwKF8qCExS7kpY4cnJa_37FMkJNkalZ3OuslLB0oRL8T4c94kdF4aeNzSFkSe2n99IBI6Ssl79vbfMZb-t06L0Q94k-_P37x7-_RJZiff4y1VGjrnrnMI2iu9l4iBBRYzNmG6eblroEMMWlgk5tysHgxB59CSNIcD9gqk1hx4n_FgOmvKsfQgWHNlPSDTRcWGWGhB2_XgNVYG2pOlQxAPqLhBHeqGTXBbPfGF9cHzixpsPr6GtbzPwhsQ_8bPxoJ7hdfn-rzztks3d6-HWURcyNTLRe0mjXjjee9Z6-gZ-H-fS4pnP9tqT7IgU6ePUWTpjoiPtLexgsAa_ctjQ",
            "e": "AQAB"
        }
    ]
}`
const jwkTestJsonLegacy = `{
    "keys": [{
        "alg": "RS256",
        "kty": "RSA",
        "use": "sig",
        "x5c": ["Ci0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBeXFaNHJ3S0Y4cUNFeFM3a3BZNGMKbkphLzM3Rk1rSk5rYWxaM091c2xMQjBvUkw4VDRjOTRrZEY0YWVOelNGa1NlMm45OUlCSTZTc2w3OXZiZk1aYgordDA2TDBROTRrKy9QMzd4NysvUkpaaWZmNHkxVkdqcm5ybk1JMml1OWw0aUJCUll6Tm1HNmVibHJvRU1NV2xnCms1dHlzSGd4QjU5Q1NOSWNEOWdxazFoeDRuL0ZnT212S3NmUWdXSE5sUFNEVFJjV0dXR2hCMi9YZ05WWUcycE8KbFF4QVBxTGhCSGVxR1RYQmJQZkdGOWNIeml4cHNQcjZHdGJ6UHdoc1EvOGJQeG9KN2hkZm4rcnp6dGtzM2Q2KwpIV1VSY3lOVExSZTBtalhqamVlOVo2K2daK0grZlM0cG5QOXRxVDdJZ1U2ZVBVV1Rwam9pUHRMZXhnc0FhL2N0CmpRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo="],
        "n": "xofiG8gsnv9-I_g-5OWTLhaZtgAGq1QEsBCPK9lmLqhuonHe8lT-nK1DM49f6J9QgaOjZ3DB50QkhBysnIFNcXFyzaYIPMoccvuHLPgdBawX4WYKm5gficD0WB0XnTt4sqTI5usFpuop9vvW44BwVGhRqMT7c11gA8TSWMBxDI4A5ARc4MuQtfm64oN-JQodSztArwb9wcmH8WrBvSUkR4pyi9MT8W27gqJ2e2Xn8jgGnswNQWOyCTN84PawOYaN-2ORHeIea1g-URln1bofcHN73vZCIrVbE6iA2D7Ybh22AVrCfunekEDEe2GZfLZLejiZiBWG7enJhcrQIzAQGw",
        "e": "AQAB",
        "kid": "12345",
        "x5t": "12345"
    }]
}`
const jwtECDSAPrivateKey = `-----BEGIN PRIVATE KEY-----
MHcCAQEEIFjaz7TJpBOHmQttPypGRh3rqaXvRpsWE/EWUiLzc6veoAoGCCqGSM49
AwEHoUQDQgAEDmKdIVHH9D5xkUiMJvo4T9H8yU+QYOIBlX5DYpJFtEvzTs4SsXYC
tFsPk7c31tOpMuS8aQiLsXR82VMLqQBf1w==
-----END PRIVATE KEY-----`
const jwtECDSAPublicKey = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDmKdIVHH9D5xkUiMJvo4T9H8yU+Q
YOIBlX5DYpJFtEvzTs4SsXYCtFsPk7c31tOpMuS8aQiLsXR82VMLqQBf1w==
-----END PUBLIC KEY-----`
// openssl genrsa -out app.rsa
const jwtRSAPrivKey = `
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAyqZ4rwKF8qCExS7kpY4cnJa/37FMkJNkalZ3OuslLB0oRL8T
4c94kdF4aeNzSFkSe2n99IBI6Ssl79vbfMZb+t06L0Q94k+/P37x7+/RJZiff4y1
VGjrnrnMI2iu9l4iBBRYzNmG6eblroEMMWlgk5tysHgxB59CSNIcD9gqk1hx4n/F
gOmvKsfQgWHNlPSDTRcWGWGhB2/XgNVYG2pOlQxAPqLhBHeqGTXBbPfGF9cHzixp
sPr6GtbzPwhsQ/8bPxoJ7hdfn+rzztks3d6+HWURcyNTLRe0mjXjjee9Z6+gZ+H+
fS4pnP9tqT7IgU6ePUWTpjoiPtLexgsAa/ctjQIDAQABAoIBAECWvnBJRZgHQUn3
oDiECup9wbnyMI0D7UVXObk1qSteP69pl1SpY6xWLyLQs7WjbhiXt7FuEc7/SaAh
Wttx/W7/g8P85Bx1fmcmdsYakXaCJpPorQKyTibQ4ReIDfvIFN9n/MWNr0ptpVbx
GonFJFrneK52IGplgCLllLwYEbnULYcJc6E25Ro8U2gQjF2r43PDa07YiDrmB/GV
QQW4HTo+CA9rdK0bP8GpXgc0wpmBhx/t/YdnDg6qhzyUMk9As7JrAzYPjHO0cRun
vhA/aG/mdMmRumY75nj7wB5U5DgstsN2ER75Pjr1xe1knftIyNm15AShCPfLaLGo
dA2IpwECgYEA5E8h6ssa7QroCGwp/N0wSJW41hFYGygbOEg6yPWTJkqmMZVduD8X
/KFqJK4LcIbFQuR28+hWJpHm/RF1AMRhbbWkAj6h02gv5izFwDiFKev5paky4Evg
G8WfUOmSZ1D+fVxwaoG0OaRZpCovUTxYig3xrI659DMeKqpQ7e8l9ekCgYEA4zql
l4P4Dn0ydr+TI/s4NHIQHkaLQAVk3OWwyKowijXd8LCtuZRA1NKSpqQ4ZXi0B17o
9zzF5jEUjws3qWv4PKWdxJu3y+h/etsg7wxUeNizbY2ooUGeMbk0tWxJihbgaI7E
XxLIT50F3Ky4EJ2cUL9GmJ+gLCw0KIaVbkiyYAUCgYEA0WyVHB76r/2VIkS1rzHm
HG7ageKfAyoi7dmzsqsxM6q+EDWHJn8Zra8TAlp0O+AkClwvkUTJ4c9sJy9gODfr
dwtrSnPRVW74oRbovo4Z+H5xHbi65mwzQsZggYP/u63cA3pL1Cbt/wH3CFN52/aS
8PAhg7vYb1yEi3Z3jgoUtCECgYEAhSPX4u9waQzyhKG7lVmdlR1AVH0BGoIOl1/+
NZWC23i0klLzd8lmM00uoHWYldwjoC38UuFJE5eudCIeeybITMC9sHWNO+z+xP2g
TnDrDePrPkXCiLnp9ziNqb/JVyAQXTNJ3Gsk84EN7j9Fmna/IJDyzHq7XyaHaTdy
VyxBWAECgYEA4jYS07bPx5UMhKiMJDqUmDfLNFD97XwPoJIkOdn6ezqeOSmlmo7t
jxHLbCmsDOAsCU/0BlLXg9wMU7n5QKSlfTVGok/PU0rq2FUXQwyKGnellrqODwFQ
YGivtXBGXk1hlVYlje1RB+W6RQuDAegI5h8vl8pYJS9JQH0wjatsDaE=
-----END RSA PRIVATE KEY-----
`
const jwtSecret = "9879879878787878"
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// identifies that field value was hidden before output to the log
const logHiddenValue = "<hidden>"
const mascot = `
.                   ╲╲╲╲╲╲
.                   ╲╲╲╲╲╲╲╲╲
.            *******╲╲╲╲╲╲╲╲╲╲╲
.           **********╲╲╲╲╲╲╲╲╲╲
.        ***************╲╲╲╲╲╲╲╲╲╲
.      ******************╲╲╲╲╲╲╲╲╲
.     ********************╲╲╲╲╲╲╲╲╲
.    ***********************╲╲╲╲╲╲╲╲
.   *************************** ╲╲╲╲╲╲
.   ****************************    ╲╲╲
.   *****      *******      ****     _______      _        _
.   ******      *****      *****    |__   __|    | |      (_)
.   ****************************       | | _   _ | | __    _   ___
.   *****************************      | || | | || |/ /   | | / _ \
.   ******************************     | || |_| ||   <  _ | || (_) |
.  ********************************    |_| \__, ||_|\_\(_)|_| \___/
. *********************************         __/ |
. ***  ************* *********  ****       |___/
.       *********************
.         *****************
.          ******* ******
.            ***** *****
.           ****** ******
`
const mascotHeaderKeyFormat = "X-Mascot-%03d"
const maxUdpBytes = 1440	// 1500(Ethernet MTU) - 60(Max UDP header size
const oAuthClientNotFound = "OAuth client not found"
const (
	oAuthClientTokensKeyPattern = "oauth-data.*oauth-client-tokens.*"
)
const oAuthNotPropagatedErr = "OAuth client list isn't available or hasn't been propagated yet."
const oauthClientIdEmpty = "client_id is required"
const oauthClientSecretEmpty = "client_secret is required"
const oauthClientSecretWrong = "client secret is wrong"
const oauthTokenEmpty = "token is required"
const (
	rateLimitEndpoint = "/tyk/rate-limits/"
)
const sampleAPI = `{
    "api_id": "test",
	"org_id": "default",
    "use_keyless": true,
    "definition": {
        "location": "header",
        "key": "version"
    },
    "auth": {
        "auth_header_name": "authorization"
	},
    "version_data": {
		"default_version": "Default",
        "not_versioned": true,
        "versions": {
            "v1": {
            	"name": "v1",
            	"use_extended_paths": true
           	}
        }
    },
    "proxy": {
        "listen_path": "/sample",
        "target_url": "` + TestHttpAny + `"
    },
	"graphql": {
      "enabled": false,
      "execution_mode": "executionEngine",
	  "version": "",
      "schema": "` + testComposedSchema + `",
      "type_field_configurations": [
        ` + testGraphQLDataSourceConfiguration + `,
        ` + testRESTDataSourceConfiguration + `
      ],
	  "engine": {
		"field_configs": [
			{
				"type_name": "Query",
				"field_name": "people",
				"disable_default_mapping": true,
				"path": [""]
			},
			{
				"type_name": "Query",
				"field_name": "headers",
				"disable_default_mapping": true,
				"path": [""]
			}
		],
		"data_sources": [
		    ` + testRESTDataSourceConfigurationV2 + `,
			` + testGraphQLDataSourceConfigurationV2 + `,
			` + testRESTHeadersDataSourceConfigurationV2 + `
		]
	},
      "playground": {
        "enabled": false,
        "path": "/playground"
      }
    }
}`
const testComposedSchema = "type Query {countries: [Country] headers: [Header]} " +
	"extend type Query {people: [Person]}" +
	"type Person {name: String country: Country} " +
	"type Country {code: String name: String} " +
	"type Header {name:String value: String}"
const testComposedSchemaNotExtended = "type Query {countries: [Country] headers: [Header] people: [Person]} " +
	"type Person {name: String country: Country} " +
	"type Country {code: String name: String} " +
	"type Header {name:String value: String}"
const testGraphQLDataSourceConfiguration = `
{
  "type_name": "Query",
  "field_name": "countries",
  "mapping": {
	"disabled": false,
	"path": "countries"
  },
  "data_source": {
	"kind": "GraphQLDataSource",
	"data_source_config": {
	  "url": "` + testGraphQLDataSource + `",
	  "method": "POST"
	}
  }
}
`
const testGraphQLDataSourceConfigurationV2 = `
{
	"kind": "GraphQL",
	"name": "countries",
	"internal": true,
	"root_fields": [
		{ "type": "Query", "fields": ["countries"] }
	],
	"config": {
		"url": "` + testGraphQLDataSource + `",
		"method": "POST"
	}
}`
const testRESTDataSourceConfiguration = `
{
 "type_name": "Query",
 "field_name": "people",
  "mapping": {
	"disabled": false,
	"path": ""
  },
  "data_source": {
    "kind": "HTTPJSONDataSource",
	"data_source_config": {
	  "url": "` + testRESTDataSource + `",
	  "method": "GET",
	  "body": "",
	  "headers": [],
	  "default_type_name": "People",
	  "status_code_type_name_mappings": [
		{
		  "status_code": 200,
		  "type_name": ""
		}
	  ]
	}
  }
}`
const testRESTDataSourceConfigurationV2 = `
{
	"kind": "REST",
	"name": "people",
	"internal": true,
	"root_fields": [
		{ "type": "Query", "fields": ["people"] }
	],
	"config": {
		"url": "` + testRESTDataSource + `",
		"method": "GET",
		"headers": {},
		"query": [],
		"body": ""
	}
}`
const testRESTDataSourceConfigurationV3 = `
{
	"kind": "REST",
	"name": "people",
	"internal": true,
	"root_fields": [
		{ "type": "Query", "fields": ["people"] }
	],
	"config": {
		"url": "` + testRESTDataSourceV3 + `",
		"method": "GET",
		"headers": {},
		"query": [],
		"body": ""
	}
}`
const testRESTHeadersDataSourceConfigurationV2 = `
{
	"kind": "REST",
	"name": "headers",
	"internal": true,
	"root_fields": [
		{ "type": "Query", "fields": ["headers"] }
	],
	"config": {
		"url": "` + testRESTHeadersDataSource + `",
		"method": "GET",
		"headers": {
			"static": "barbaz",
			"injected": "{{ .request.headers.injected }}",
			"context": "$tyk_context.headers_From_Request",
			"does-exist-already": "ds-does-exist-already"
		},
		"query": [],
		"body": ""
	}
}`

Vars

var (
	// ErrEventHandlerDisabled is returned when the event handler is disabled.
	ErrEventHandlerDisabled = errors.New("event handler disabled")
)
var (
	ErrPoliciesFetchFailed = errors.New("fetch policies request login failure")
)
var (
	ErrRequestMalformed = errors.New("request malformed")
)

GatewayFireSystemEvent declared as global variable, set during gw start

var GatewayFireSystemEvent func(name apidef.TykEvent, meta interface{})
var GetJWK = getJWK
var JWKCache cache.Repository = cache.New(240, 30)
var LoopHostRE = regexp.MustCompile("tyk://([^/]+)")
var NonAlphaNumRE = regexp.MustCompile("[^A-Za-z0-9]+")
var TykErrors = make(map[string]config.TykError)
var (
	grpcConnection	*grpc.ClientConn
	grpcClient	coprocess.DispatcherClient
)
var (
	GlobalRate		= ratecounter.NewRateCounter(1 * time.Second)
	orgSessionExpiryCache	singleflight.Group
)
var (
	globalMu	sync.Mutex

	log		= logger.Get()
	mainLog		= log.WithField("prefix", "main")
	pubSubLog	= log.WithField("prefix", "pub-sub")
	rawLog		= logger.GetRaw()

	memProfFile	*os.File

	// confPaths is the series of paths to try to use as config files. The
	// first one to exist will be used. If none exists, a default config
	// will be written to the first path in the list.
	//
	// When --conf=foo is used, this will be replaced by []string{"foo"}.
	confPaths	= []string{
		"tyk.conf",
		// TODO: add ~/.config/tyk/tyk.conf here?
		"/etc/tyk/tyk.conf",
	}

	ErrSyncResourceNotKnown	= errors.New("unknown resource to sync")
)
var (
	// List of common OAuth Client ID claims used by IDPs:
	oauthClientIDClaims	= []string{
		"clientId",	// Keycloak
		"cid",		// OKTA
		"client_id",	// Gluu
	}

	ErrNoSuitableUserIDClaimFound	= errors.New("no suitable claims for user ID were found")
	ErrEmptyUserIDInSubClaim	= errors.New("found an empty user ID in sub claim")
)
var (
	ProxyingRequestFailedErr	= errors.New("there was a problem proxying the request")
	GraphQLDepthLimitExceededErr	= errors.New("depth limit exceeded")
)
var (
	externalOAuthJWKCache		cache.Repository	= cache.New(240, 30)
	externalOAuthIntrospectionCache	*introspectionCache
	ErrTokenValidationFailed	= errors.New("error happened during the access token validation")
	ErrKIDNotAString		= errors.New("kid is not a string")
	ErrNoMatchingKIDFound		= errors.New("no matching KID could be found")
)
var (
	bundleBackoffMultiplier	float64	= 2
	bundleMaxBackoffRetries	uint64	= 4
)
var (
	supportedDrivers	= []apidef.MiddlewareDriver{apidef.PythonDriver, apidef.LuaDriver, apidef.GrpcDriver}
	loadedDrivers		= map[apidef.MiddlewareDriver]coprocess.Dispatcher{}
)
var (
	VERSION	= build.Version
	Commit	= build.Commit
)
var (
	ctxData	= httpctx.NewValue[map[string]any](ctx.ContextData)

	ctxGetData	= ctxData.Get
	ctxSetData	= ctxData.Set

	setContext	= core.SetContext

	// how is type safety avoided: exhibit A, old school generics
	setCtxValue	= func(h *http.Request, key, value any) {
		ctxvalue := httpctx.NewValue[any](key)
		h = ctxvalue.Set(h, value)
	}

	EncodeRequestToEvent	= event.EncodeRequestToEvent
)
var (
	onceStartAllHostsDown	sync.Once

	allHostsDownURL	string
)
var applicationGCStats = debug.GCStats{}
var basicAuthCache = cache.New(60, 3600)
var cacheGroup singleflight.Group
var certLog = log.WithField("prefix", "certs")

Deprecated: use tls.CipherSuites() now

var cipherSuites = map[string]uint16{
	"TLS_RSA_WITH_RC4_128_SHA":			0x0005,
	"TLS_RSA_WITH_3DES_EDE_CBC_SHA":		0x000a,
	"TLS_RSA_WITH_AES_128_CBC_SHA":			0x002f,
	"TLS_RSA_WITH_AES_256_CBC_SHA":			0x0035,
	"TLS_RSA_WITH_AES_128_CBC_SHA256":		0x003c,
	"TLS_RSA_WITH_AES_128_GCM_SHA256":		0x009c,
	"TLS_RSA_WITH_AES_256_GCM_SHA384":		0x009d,
	"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":		0xc007,
	"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":		0xc009,
	"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":		0xc00a,
	"TLS_ECDHE_RSA_WITH_RC4_128_SHA":		0xc011,
	"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":		0xc012,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":		0xc013,
	"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":		0xc014,
	"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256":	0xc023,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256":	0xc027,
	"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":	0xc02f,
	"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256":	0xc02b,
	"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":	0xc030,
	"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384":	0xc02c,
	"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":		0xcca8,
	"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":	0xcca9,
}
var consulMatch = regexp.MustCompile(`\$secret_consul.([A-Za-z0-9\/\-\.]+)`)
var contextMatch = regexp.MustCompile(`\$tyk_context.([A-Za-z0-9_\-\.]+)`)
var corsHeaders = []string{
	"Access-Control-Allow-Origin",
	"Access-Control-Expose-Headers",
	"Access-Control-Max-Age",
	"Access-Control-Allow-Credentials",
	"Access-Control-Allow-Methods",
	"Access-Control-Allow-Headers"}
var createOauthClientSecret = func() string {
	secret := uuid.New()
	return base64.StdEncoding.EncodeToString([]byte(secret))
}
var dashClient *http.Client
var dashLog = log.WithField("prefix", "dashboard")
var defaultStatsDOptions = StatsDSinkOptions{SanitizationFunc: sanitizeKey}
var defaultUserAgent = "Tyk/" + VERSION
var defaultWorkerPoolSize = runtime.NumCPU()
var (
	dispatcherFuncs = map[string]interface{}{
		"Login": func(clientAddr, userKey string) bool {
			return false
		},
		"LoginWithGroup": func(clientAddr string, groupData *model.GroupLoginRequest) bool {
			return false
		},
		"GetKey": func(keyName string) (string, error) {
			return "", nil
		},
		"SetKey": func(ibd *model.InboundData) error {
			return nil
		},
		"GetExp": func(keyName string) (int64, error) {
			return 0, nil
		},
		"GetKeys": func(keyName string) ([]string, error) {
			return nil, nil
		},
		"DeleteKey": func(keyName string) (bool, error) {
			return true, nil
		},
		"DeleteRawKey": func(keyName string) (bool, error) {
			return true, nil
		},
		"GetKeysAndValues": func(searchString string) (*model.KeysValuesPair, error) {
			return nil, nil
		},
		"GetKeysAndValuesWithFilter": func(searchString string) (*model.KeysValuesPair, error) {
			return nil, nil
		},
		"DeleteKeys": func(keys []string) (bool, error) {
			return true, nil
		},
		"DeleteRawKeys": func(keys []string) (bool, error) {
			return true, nil
		},
		"Decrement": func(keyName string) error {
			return nil
		},
		"IncrememntWithExpire": func(ibd *model.InboundData) (int64, error) {
			return 0, nil
		},
		"AppendToSet": func(ibd *model.InboundData) error {
			return nil
		},
		"SetRollingWindow": func(ibd *model.InboundData) (int, error) {
			return 0, nil
		},
		"GetApiDefinitions": func(dr *model.DefRequest) (string, error) {
			return "", nil
		},
		"GetPolicies": func(orgId string) (string, error) {
			return "", nil
		},
		"PurgeAnalyticsData": func(data string) error {
			return nil
		},
		"CheckReload": func(clientAddr, orgId string) (bool, error) {
			return false, nil
		},
		"GetKeySpaceUpdate": func(clientAddr, orgId string) ([]string, error) {
			return nil, nil
		},
		"GetGroupKeySpaceUpdate": func(clientAddr string, groupData *model.GroupKeySpaceRequest) ([]string, error) {
			return nil, nil
		},
		"Ping": func() bool {
			return false
		},
		"Disconnect": func(clientAddr string, groupData *model.GroupLoginRequest) error {
			return nil
		},
	}
)
var dollarMatch = regexp.MustCompile(`\$\d+`)
var envRegex = regexp.MustCompile(`env://([^"]+)`)
var envValueMatch = regexp.MustCompile(`\$secret_env.([A-Za-z0-9_\-\.]+)`)
var errCustomBodyResponse = errors.New("errCustomBodyResponse")
var errUnauthorized = errors.New("Unauthorized")
var getIpAddress = netutil.GetIpAddress

Hop-by-hop headers. These are removed when sent to the backend. http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html

var hopHeaders = []string{
	"Connection",
	"Proxy-Connection",	// non-standard but still sent by libcurl and rejected by e.g. google
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te",		// canonicalized version of "TE"
	"Trailer",	// not Trailers per URL above; http://www.rfc-editor.org/errata_search.php?eid=4522
	"Transfer-Encoding",
	"Upgrade",
}

httpScheme matches http://* and https://*, case insensitive

var httpScheme = regexp.MustCompile(`^(?i)https?://`)
var idleConnTimeout = 90
var instrument = health.NewStream()
var instrumentationEnabled bool

memConnClient is used to make request to internal APIs.

var memConnClient = &http.Client{
	Transport: &http.Transport{
		DialContext: func(ctx context.Context, _, addr string) (net.Conn, error) {
			provider, err := getMemConnProvider(addr)
			if err != nil {
				return nil, err
			}
			return provider.DialContext(ctx, inMemNetworkType, inMemNetworkName)
		},
	},
}
var memConnProviders = &struct {
	mtx	sync.RWMutex
	m	map[string]*memConnProvider
}{
	m: make(map[string]*memConnProvider),
}
var metaMatch = regexp.MustCompile(`\$tyk_meta.([A-Za-z0-9_\-\.]+)`)
var oneMascot sync.Once
var orgActiveMap sync.Map
var orgChanMap = orgChanMapMu{channels: map[string](chan bool){}}
var playgroundTemplate *texttemplate.Template
var redisInsecureWarn sync.Once
var sdMu sync.RWMutex
var secretsConfMatch = regexp.MustCompile(`\$secret_conf.([A-Za-z0-9[.\-\_]+)`)

As for the HTTP methods spec:

HTTP request bodies are theoretically allowed for all methods except TRACE,
however they are not commonly used except in PUT, POST and PATCH. Because of this,
they may not be supported properly by some client frameworks, and you should not allow
request bodies for GET, DELETE, TRACE, OPTIONS and HEAD methods.

var skippedMethods = map[string]struct{}{
	http.MethodGet:		{},
	http.MethodDelete:	{},
	http.MethodTrace:	{},
	http.MethodOptions:	{},
	http.MethodHead:	{},
}
var supportedAlgorithms = []string{"hmac-sha1", "hmac-sha256", "hmac-sha384", "hmac-sha512", "rsa-sha256"}
var tlsConfigCache = cache.New(60, 3600)
var tlsConfigMu sync.Mutex
var vaultMatch = regexp.MustCompile(`\$secret_vault.([A-Za-z0-9\/\-\.]+)`)

Types

APIAllCertificateBasics

This type doesn't have documentation.

Field name Field type Comment
Certs

[]*certs.CertificateBasics

No comment on field.
type APIAllCertificateBasics struct {
	Certs []*certs.CertificateBasics `json:"certs"`
}

APIAllCertificates

This type doesn't have documentation.

Field name Field type Comment
CertIDs

[]string

No comment on field.
type APIAllCertificates struct {
	CertIDs []string `json:"certs"`
}

APICertificateStatusMessage

This type doesn't have documentation.

Field name Field type Comment
CertID

string

No comment on field.
Status

string

No comment on field.
Message

string

No comment on field.
type APICertificateStatusMessage struct {
	CertID	string	`json:"id"`
	Status	string	`json:"status"`
	Message	string	`json:"message"`
}

APIDefinitionLoader

APIDefinitionLoader will load an Api definition from a storage system.

Field name Field type Comment
Gw

*Gateway

No comment on field.
type APIDefinitionLoader struct {
	Gw *Gateway `json:"-"`
}

APIError

APIError is generic error object returned if there is something wrong with the request

Field name Field type Comment
Message

htmltemplate.HTML

No comment on field.
type APIError struct {
	Message htmltemplate.HTML
}

APISpec

APISpec represents a path specification for an API, to avoid enumerating multiple nested lists, a single flattened URL list is checked for matching paths and then it's status evaluated if found.

Field name Field type Comment

*apidef.APIDefinition

No comment on field.
OAS

oas.OAS

No comment on field.

sync.RWMutex

No comment on field.
Checksum

string

No comment on field.
RxPaths

map[string][]URLSpec

No comment on field.
WhiteListEnabled

map[string]bool

No comment on field.
target

*url.URL

No comment on field.
AuthManager

SessionHandler

No comment on field.
OAuthManager

OAuthManagerInterface

No comment on field.
OrgSessionManager

SessionHandler

No comment on field.
EventPaths

map[apidef.TykEvent][]config.TykEventHandler

No comment on field.
Health

HealthChecker

No comment on field.
JSVM

JSVM

No comment on field.
ResponseChain

[]TykResponseHandler

No comment on field.
RoundRobin

RoundRobin

No comment on field.
URLRewriteEnabled

bool

No comment on field.
CircuitBreakerEnabled

bool

No comment on field.
EnforcedTimeoutEnabled

bool

No comment on field.
LastGoodHostList

*apidef.HostList

No comment on field.
HasRun

bool

No comment on field.
ServiceRefreshInProgress

bool

No comment on field.
HTTPTransport

*TykRoundTripper

No comment on field.
HTTPTransportCreated

time.Time

No comment on field.
WSTransport

http.RoundTripper

No comment on field.
WSTransportCreated

time.Time

No comment on field.
GlobalConfig

config.Config

No comment on field.
OrgHasNoSession

bool

No comment on field.
AnalyticsPluginConfig

*GoAnalyticsPlugin

No comment on field.
middlewareChain

*ChainObject

No comment on field.
unloadHooks

[]func()

No comment on field.
network

analytics.NetworkStats

No comment on field.
GraphEngine

graphengine.Engine

No comment on field.
HasMock

bool

No comment on field.
HasValidateRequest

bool

No comment on field.
OASRouter

routers.Router

No comment on field.
type APISpec struct {
	*apidef.APIDefinition
	OAS	oas.OAS

	sync.RWMutex

	Checksum		string
	RxPaths			map[string][]URLSpec
	WhiteListEnabled	map[string]bool
	target			*url.URL
	AuthManager		SessionHandler
	OAuthManager		OAuthManagerInterface

	OrgSessionManager		SessionHandler
	EventPaths			map[apidef.TykEvent][]config.TykEventHandler
	Health				HealthChecker
	JSVM				JSVM
	ResponseChain			[]TykResponseHandler
	RoundRobin			RoundRobin
	URLRewriteEnabled		bool
	CircuitBreakerEnabled		bool
	EnforcedTimeoutEnabled		bool
	LastGoodHostList		*apidef.HostList
	HasRun				bool
	ServiceRefreshInProgress	bool
	HTTPTransport			*TykRoundTripper
	HTTPTransportCreated		time.Time
	WSTransport			http.RoundTripper
	WSTransportCreated		time.Time
	GlobalConfig			config.Config
	OrgHasNoSession			bool
	AnalyticsPluginConfig		*GoAnalyticsPlugin

	middlewareChain	*ChainObject
	unloadHooks	[]func()

	network	analytics.NetworkStats

	GraphEngine	graphengine.Engine

	HasMock			bool
	HasValidateRequest	bool
	OASRouter		routers.Router
}

AccessRightsCheck

AccessRightsCheck is a middleware that will check if the key bing used to access the API has permission to access the specific version. If no permission data is in the user.SessionState, then it is assumed that the user can go through.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type AccessRightsCheck struct {
	*BaseMiddleware
}

AuthKey

KeyExists will check if the key being used to access the API is in the request data, and then if the key is in the storage engine

Field name Field type Comment

*BaseMiddleware

No comment on field.
type AuthKey struct {
	*BaseMiddleware
}

BaseExtractor

BaseExtractor is the base structure for an ID extractor, it implements the IdExtractor interface. Other extractors may override some of its methods.

Field name Field type Comment
Config

*apidef.MiddlewareIdExtractor

No comment on field.
IDExtractorConfig

apidef.IDExtractorConfig

No comment on field.

*BaseMiddleware

No comment on field.
Spec

*APISpec

No comment on field.
type BaseExtractor struct {
	Config			*apidef.MiddlewareIdExtractor
	IDExtractorConfig	apidef.IDExtractorConfig
	*BaseMiddleware

	Spec	*APISpec
}

BaseMiddleware

BaseMiddleware wraps up the ApiSpec and Proxy objects to be included in a middleware handler, this can probably be handled better.

Field name Field type Comment
Spec

*APISpec

No comment on field.
Proxy

ReturningHttpHandler

No comment on field.
Gw

*Gateway

No comment on field.
loggerMu

sync.Mutex

No comment on field.
logger

*logrus.Entry

No comment on field.
type BaseMiddleware struct {
	Spec	*APISpec
	Proxy	ReturningHttpHandler
	Gw	*Gateway	`json:"-"`

	loggerMu	sync.Mutex
	logger		*logrus.Entry
}

BaseTykResponseHandler

This type doesn't have documentation.

Field name Field type Comment
Spec

*APISpec

No comment on field.
Gw

*Gateway

No comment on field.
type BaseTykResponseHandler struct {
	Spec	*APISpec	`json:"-"`
	Gw	*Gateway	`json:"-"`
}

BasicAuthKeyIsValid

BasicAuthKeyIsValid uses a username instead of

Field name Field type Comment

*BaseMiddleware

No comment on field.
bodyUserRegexp

*regexp.Regexp

No comment on field.
bodyPasswordRegexp

*regexp.Regexp

No comment on field.
type BasicAuthKeyIsValid struct {
	*BaseMiddleware

	bodyUserRegexp		*regexp.Regexp
	bodyPasswordRegexp	*regexp.Regexp
}

BatchReplyUnit

BatchReplyUnit encodes a request suitable for replying to a batch request

Field name Field type Comment
RelativeURL

string

No comment on field.
Code

int

No comment on field.
Headers

http.Header

No comment on field.
Body

string

No comment on field.
type BatchReplyUnit struct {
	RelativeURL	string		`json:"relative_url"`
	Code		int		`json:"code"`
	Headers		http.Header	`json:"headers"`
	Body		string		`json:"body"`
}

BatchRequestHandler

BatchRequestHandler handles batch requests on /tyk/batch for any API Definition that has the feature enabled

Field name Field type Comment
Gw

*Gateway

No comment on field.
API

*APISpec

No comment on field.
type BatchRequestHandler struct {
	Gw	*Gateway	`json:"-"`
	API	*APISpec
}

BatchRequestStructure

BatchRequestStructure defines a batch request order

Field name Field type Comment
Requests

[]RequestDefinition

No comment on field.
SuppressParallelExecution

bool

No comment on field.
type BatchRequestStructure struct {
	Requests			[]RequestDefinition	`json:"requests"`
	SuppressParallelExecution	bool			`json:"suppress_parallel_execution"`
}

Bundle

Bundle is the basic bundle data structure, it holds the bundle name and the data.

Field name Field type Comment
Name

string

No comment on field.
Data

[]byte

No comment on field.
Path

string

No comment on field.
Spec

*APISpec

No comment on field.
Manifest

apidef.BundleManifest

No comment on field.
Gw

*Gateway

No comment on field.
type Bundle struct {
	Name		string
	Data		[]byte
	Path		string
	Spec		*APISpec
	Manifest	apidef.BundleManifest
	Gw		*Gateway	`json:"-"`
}

BundleGetter

BundleGetter is used for downloading bundle data, see HttpBundleGetter for reference.

Field name Field type Comment
type

any

No comment on field.
type BundleGetter interface {
	Get() ([]byte, error)
}

BundleSaver

BundleSaver is an interface used by bundle saver structures.

Field name Field type Comment
type

any

No comment on field.
type BundleSaver interface {
	Save(*Bundle, string, *APISpec) error
}

CertificateCheckMW

CertificateCheckMW is used if domain was not detected or multiple APIs bind on the same domain. In this case authentification check happens not on TLS side but on HTTP level using this middleware

Field name Field type Comment

*BaseMiddleware

No comment on field.
type CertificateCheckMW struct {
	*BaseMiddleware
}

ChainObject

This type doesn't have documentation.

Field name Field type Comment
ThisHandler

http.Handler

No comment on field.
RateLimitChain

http.Handler

No comment on field.
Open

bool

No comment on field.
Skip

bool

No comment on field.
type ChainObject struct {
	ThisHandler	http.Handler
	RateLimitChain	http.Handler
	Open		bool
	Skip		bool
}

CoProcessEventHandler

This type doesn't have documentation.

Field name Field type Comment
methodName

string

No comment on field.
Spec

*APISpec

No comment on field.
SpecJSON

json.RawMessage

No comment on field.
type CoProcessEventHandler struct {
	methodName	string
	Spec		*APISpec
	SpecJSON	json.RawMessage
}

CoProcessEventWrapper

This type doesn't have documentation.

Field name Field type Comment
Event

config.EventMessage

No comment on field.
Handler

string

No comment on field.
SpecJSON

*json.RawMessage

No comment on field.
type CoProcessEventWrapper struct {
	Event		config.EventMessage	`json:"message"`
	Handler		string			`json:"handler_name"`
	SpecJSON	*json.RawMessage	`json:"spec"`
}

CoProcessMiddleware

CoProcessMiddleware is the basic CP middleware struct.

Field name Field type Comment

*BaseMiddleware

No comment on field.
HookType

coprocess.HookType

No comment on field.
HookName

string

No comment on field.
MiddlewareDriver

apidef.MiddlewareDriver

No comment on field.
RawBodyOnly

bool

No comment on field.
successHandler

*SuccessHandler

No comment on field.
type CoProcessMiddleware struct {
	*BaseMiddleware

	HookType		coprocess.HookType
	HookName		string
	MiddlewareDriver	apidef.MiddlewareDriver
	RawBodyOnly		bool

	successHandler	*SuccessHandler
}

CoProcessor

CoProcessor represents a CoProcess during the request.

Field name Field type Comment
Middleware

*CoProcessMiddleware

No comment on field.
type CoProcessor struct {
	Middleware *CoProcessMiddleware
}

ComplexityFailReason

This type doesn't have documentation.

Field name Field type Comment
type

int

No comment on field.
type ComplexityFailReason int

ConfigPayload

This type doesn't have documentation.

Field name Field type Comment
Configuration

config.Config

No comment on field.
ForHostname

string

No comment on field.
ForNodeID

string

No comment on field.
TimeStamp

int64

No comment on field.
type ConfigPayload struct {
	Configuration	config.Config
	ForHostname	string
	ForNodeID	string
	TimeStamp	int64
}

CustomMiddlewareResponseHook

This type doesn't have documentation.

Field name Field type Comment

BaseTykResponseHandler

No comment on field.
mw

*CoProcessMiddleware

No comment on field.
type CustomMiddlewareResponseHook struct {
	BaseTykResponseHandler
	mw	*CoProcessMiddleware
}

DBAccessDefinition

This type doesn't have documentation.

Field name Field type Comment
APIName

string

No comment on field.
APIID

string

No comment on field.
Versions

[]string

No comment on field.
AllowedURLs

[]user.AccessSpec

No comment on field.
RestrictedTypes

[]graphql.Type

No comment on field.
AllowedTypes

[]graphql.Type

No comment on field.
DisableIntrospection

bool

No comment on field.
FieldAccessRights

[]user.FieldAccessDefinition

No comment on field.
Limit

*user.APILimit

No comment on field.
Endpoints

user.Endpoints

Endpoints contains endpoint rate limit settings.

type DBAccessDefinition struct {
	APIName			string				`json:"api_name"`
	APIID			string				`json:"api_id"`
	Versions		[]string			`json:"versions"`
	AllowedURLs		[]user.AccessSpec		`bson:"allowed_urls" json:"allowed_urls"`	// mapped string MUST be a valid regex
	RestrictedTypes		[]graphql.Type			`json:"restricted_types"`
	AllowedTypes		[]graphql.Type			`json:"allowed_types"`
	DisableIntrospection	bool				`json:"disable_introspection"`
	FieldAccessRights	[]user.FieldAccessDefinition	`json:"field_access_rights"`
	Limit			*user.APILimit			`json:"limit"`

	// Endpoints contains endpoint rate limit settings.
	Endpoints	user.Endpoints	`json:"endpoints,omitempty"`
}

DBPolicy

This type doesn't have documentation.

Field name Field type Comment

user.Policy

No comment on field.
AccessRights

map[string]DBAccessDefinition

No comment on field.
type DBPolicy struct {
	user.Policy
	AccessRights	map[string]DBAccessDefinition	`bson:"access_rights" json:"access_rights"`
}

DashboardServiceSender

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type DashboardServiceSender interface {
	Init() error
	Register() error
	DeRegister() error
	StartBeating() error
	StopBeating()
	Ping() error
	NotifyDashboardOfEvent(interface{}) error
}

DefaultHealthChecker

This type doesn't have documentation.

Field name Field type Comment
Gw

*Gateway

No comment on field.
storage

storage.Handler

No comment on field.
APIID

string

No comment on field.
type DefaultHealthChecker struct {
	Gw	*Gateway	`json:"-"`
	storage	storage.Handler
	APIID	string
}

DefaultKeyGenerator

This type doesn't have documentation.

Field name Field type Comment
Gw

*Gateway

No comment on field.
type DefaultKeyGenerator struct {
	Gw *Gateway `json:"-"`
}

DefaultSessionManager

This type doesn't have documentation.

Field name Field type Comment
store

storage.Handler

No comment on field.
orgID

string

No comment on field.
Gw

*Gateway

No comment on field.
type DefaultSessionManager struct {
	store	storage.Handler
	orgID	string
	Gw	*Gateway	`json:"-"`
}

DummyProxyHandler

This type doesn't have documentation.

Field name Field type Comment
SH

SuccessHandler

No comment on field.
Gw

*Gateway

No comment on field.
type DummyProxyHandler struct {
	SH	SuccessHandler
	Gw	*Gateway	`json:"-"`
}

DynamicMiddleware

DynamicMiddleware is a generic middleware that will execute JS code before continuing

Field name Field type Comment

*BaseMiddleware

No comment on field.
MiddlewareClassName

string

No comment on field.
Pre

bool

No comment on field.
UseSession

bool

No comment on field.
Auth

bool

No comment on field.
type DynamicMiddleware struct {
	*BaseMiddleware

	MiddlewareClassName	string
	Pre			bool
	UseSession		bool
	Auth			bool
}

EndPointCacheMeta

This type doesn't have documentation.

Field name Field type Comment
Method

string

No comment on field.
CacheKeyRegex

string

No comment on field.
CacheOnlyResponseCodes

[]int

No comment on field.
Timeout

int64

No comment on field.
type EndPointCacheMeta struct {
	Method			string
	CacheKeyRegex		string
	CacheOnlyResponseCodes	[]int
	Timeout			int64
}

ErrorHandler

ErrorHandler is invoked whenever there is an issue with a proxied request, most middleware will invoke the ErrorHandler if something is wrong with the request and halt the request processing through the chain

Field name Field type Comment

*BaseMiddleware

No comment on field.
type ErrorHandler struct {
	*BaseMiddleware
}

EventCurcuitBreakerMeta

EventCurcuitBreakerMeta is the event status for a circuit breaker tripping

Field name Field type Comment

EventMetaDefault

No comment on field.
Path

string

No comment on field.
APIID

string

No comment on field.
CircuitEvent

circuit.BreakerEvent

No comment on field.
type EventCurcuitBreakerMeta struct {
	EventMetaDefault
	Path		string
	APIID		string
	CircuitEvent	circuit.BreakerEvent
}

EventHostStatusMeta

This type doesn't have documentation.

Field name Field type Comment

EventMetaDefault

No comment on field.
HostInfo

HostHealthReport

No comment on field.
type EventHostStatusMeta struct {
	EventMetaDefault
	HostInfo	HostHealthReport
}

EventKeyFailureMeta

EventKeyFailureMeta is the metadata structure for any failure related to a key, such as quota or auth failures.

Field name Field type Comment

EventMetaDefault

No comment on field.
Path

string

No comment on field.
Origin

string

No comment on field.
Key

string

No comment on field.
type EventKeyFailureMeta struct {
	EventMetaDefault
	Path	string
	Origin	string
	Key	string
}

EventMetaDefault

This type doesn't have documentation.

Field name Field type Comment
type

model.EventMetaDefault

No comment on field.
type EventMetaDefault = model.EventMetaDefault

EventTokenMeta

This type doesn't have documentation.

Field name Field type Comment

EventMetaDefault

No comment on field.
Org

string

No comment on field.
Key

string

No comment on field.
type EventTokenMeta struct {
	EventMetaDefault
	Org	string
	Key	string
}

EventTriggerExceededMeta

This type doesn't have documentation.

Field name Field type Comment

EventMetaDefault

No comment on field.
OrgID

string

No comment on field.
Key

string

No comment on field.
TriggerLimit

int64

No comment on field.
UsagePercentage

int64

No comment on field.
type EventTriggerExceededMeta struct {
	EventMetaDefault
	OrgID		string	`json:"org_id"`
	Key		string	`json:"key"`
	TriggerLimit	int64	`json:"trigger_limit"`
	UsagePercentage	int64	`json:"usage_percentage"`
}

EventVersionFailureMeta

EventVersionFailureMeta is the metadata structure for an auth failure (EventKeyExpired)

Field name Field type Comment

EventMetaDefault

No comment on field.
Path

string

No comment on field.
Origin

string

No comment on field.
Key

string

No comment on field.
Reason

string

No comment on field.
type EventVersionFailureMeta struct {
	EventMetaDefault
	Path	string
	Origin	string
	Key	string
	Reason	string
}

ExtendedCircuitBreakerMeta

This type doesn't have documentation.

Field name Field type Comment

apidef.CircuitBreakerMeta

No comment on field.
CB

*circuit.Breaker

No comment on field.
type ExtendedCircuitBreakerMeta struct {
	apidef.CircuitBreakerMeta
	CB	*circuit.Breaker	`json:"-"`
}

ExtendedOsinClientInterface

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type ExtendedOsinClientInterface interface {
	osin.Client
	GetDescription() string
}

ExtendedOsinStorageInterface

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type ExtendedOsinStorageInterface interface {
	osin.Storage

	// Create OAuth clients
	SetClient(id string, orgID string, client osin.Client, ignorePrefix bool) error

	// Custom getter to handle prefixing issues in Redis
	GetClientNoPrefix(id string) (osin.Client, error)

	GetClientTokens(id string) ([]OAuthClientToken, error)
	GetPaginatedClientTokens(id string, page int) ([]OAuthClientToken, int, error)

	GetExtendedClient(id string) (ExtendedOsinClientInterface, error)

	// Custom getter to handle prefixing issues in Redis
	GetExtendedClientNoPrefix(id string) (ExtendedOsinClientInterface, error)

	GetClients(filter string, orgID string, ignorePrefix bool) ([]ExtendedOsinClientInterface, error)

	DeleteClient(id string, orgID string, ignorePrefix bool) error

	// GetUser retrieves a Basic Access user token type from the key store
	GetUser(string) (*user.SessionState, error)

	// SetUser updates a Basic Access user token type in the key store
	SetUser(string, *user.SessionState, int64) error
}

ExternalOAuthMiddleware

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type ExternalOAuthMiddleware struct {
	*BaseMiddleware
}

FileBundleGetter

FileBundleGetter is a BundleGetter for testing.

Field name Field type Comment
URL

string

No comment on field.
InsecureSkipVerify

bool

No comment on field.
type FileBundleGetter struct {
	URL			string
	InsecureSkipVerify	bool
}

GRPCDispatcher

GRPCDispatcher implements a coprocess.Dispatcher

Field name Field type Comment

coprocess.Dispatcher

No comment on field.
type GRPCDispatcher struct {
	coprocess.Dispatcher
}

Gateway

This type doesn't have documentation.

Field name Field type Comment
DefaultProxyMux

*proxyMux

No comment on field.
config

atomic.Value

No comment on field.
configMu

sync.Mutex

No comment on field.
ctx

context.Context

No comment on field.
nodeIDMu

sync.Mutex

No comment on field.
nodeID

string

No comment on field.
drlOnce

sync.Once

No comment on field.
DRLManager

*drl.DRL

No comment on field.
reloadMu

sync.Mutex

No comment on field.
Analytics

RedisAnalyticsHandler

No comment on field.
GlobalEventsJSVM

JSVM

No comment on field.
MainNotifier

RedisNotifier

No comment on field.
DefaultOrgStore

DefaultSessionManager

No comment on field.
DefaultQuotaStore

DefaultSessionManager

No comment on field.
GlobalSessionManager

SessionHandler

No comment on field.
MonitoringHandler

config.TykEventHandler

No comment on field.
RPCListener

RPCStorageHandler

No comment on field.
DashService

DashboardServiceSender

No comment on field.
CertificateManager

certs.CertificateManager

No comment on field.
GlobalHostChecker

*HostCheckerManager

No comment on field.
ConnectionWatcher

*httputil.ConnectionWatcher

No comment on field.
HostCheckTicker

chan struct{}

No comment on field.
HostCheckerClient

*http.Client

No comment on field.
TracerProvider

otel.TracerProvider

No comment on field.
NewRelicApplication

*newrelic.Application

No comment on field.
keyGen

DefaultKeyGenerator

No comment on field.
SessionLimiter

SessionLimiter

No comment on field.
SessionMonitor

Monitor

No comment on field.
RPCGlobalCache

cache.Repository

RPCGlobalCache stores keys

RPCCertCache

cache.Repository

RPCCertCache stores certificates

SessionCache

cache.Repository

key session memory cache

ExpiryCache

cache.Repository

org session memory cache

UtilCache

cache.Repository

memory cache to store arbitrary items

ServiceCache

cache.Repository

ServiceCache is the service discovery cache

ServiceNonce

string

Nonce to use when interacting with the dashboard service

ServiceNonceMutex

sync.RWMutex

No comment on field.
apisMu

sync.RWMutex

No comment on field.
apiSpecs

[]*APISpec

No comment on field.
apisByID

map[string]*APISpec

No comment on field.
apisHandlesByID

*sync.Map

No comment on field.
policiesMu

sync.RWMutex

No comment on field.
policiesByID

map[string]user.Policy

No comment on field.
dnsCacheManager

dnscache.IDnsCacheManager

No comment on field.
consulKVStore

kv.Store

No comment on field.
vaultKVStore

kv.Store

No comment on field.
signatureVerifier

atomic.Pointer[goverify.Verifier]

signatureVerifier is used to verify signatures with config.PublicKeyPath.

RedisPurgeOnce

sync.Once

No comment on field.
RpcPurgeOnce

sync.Once

No comment on field.
OnConnect

func()

OnConnect this is a callback which is called whenever we transition redis Disconnected to connected

SessionID

string

SessionID is the unique session id which is used while connecting to dashboard to prevent multiple node allocation.

runningTestsMu

sync.RWMutex

No comment on field.
testMode

bool

No comment on field.
reloadQueue

chan func()

reloadQueue is used by reloadURLStructure to queue a reload. It's not buffered, as reloadQueueLoop should pick these up immediately.

requeueLock

sync.Mutex

No comment on field.
requeue

[]func()

This is a list of callbacks to execute on the next reload. It is protected by requeueLock for concurrent use.

ReloadTestCase

*ReloadMachinery

ReloadTestCase use this when in any test for gateway reloads

TestBundles

map[string]map[string]string

map[bundleName]map[fileName]fileContent used for tests

TestBundleMu

sync.Mutex

No comment on field.
templates

*htmltemplate.Template

No comment on field.
templatesRaw

*texttemplate.Template

No comment on field.
StorageConnectionHandler

*storage.ConnectionHandler

RedisController keeps track of redis connection and singleton

hostDetails

model.HostDetails

No comment on field.
healthCheckInfo

atomic.Value

No comment on field.
dialCtxFn

test.DialContext

No comment on field.
type Gateway struct {
	DefaultProxyMux	*proxyMux
	config		atomic.Value
	configMu	sync.Mutex

	ctx	context.Context

	nodeIDMu	sync.Mutex
	nodeID		string

	drlOnce		sync.Once
	DRLManager	*drl.DRL
	reloadMu	sync.Mutex

	Analytics		RedisAnalyticsHandler
	GlobalEventsJSVM	JSVM
	MainNotifier		RedisNotifier
	DefaultOrgStore		DefaultSessionManager
	DefaultQuotaStore	DefaultSessionManager
	GlobalSessionManager	SessionHandler
	MonitoringHandler	config.TykEventHandler
	RPCListener		RPCStorageHandler
	DashService		DashboardServiceSender
	CertificateManager	certs.CertificateManager
	GlobalHostChecker	*HostCheckerManager
	ConnectionWatcher	*httputil.ConnectionWatcher
	HostCheckTicker		chan struct{}
	HostCheckerClient	*http.Client
	TracerProvider		otel.TracerProvider
	NewRelicApplication	*newrelic.Application

	keyGen	DefaultKeyGenerator

	SessionLimiter	SessionLimiter
	SessionMonitor	Monitor

	// RPCGlobalCache stores keys
	RPCGlobalCache	cache.Repository
	// RPCCertCache stores certificates
	RPCCertCache	cache.Repository
	// key session memory cache
	SessionCache	cache.Repository
	// org session memory cache
	ExpiryCache	cache.Repository
	// memory cache to store arbitrary items
	UtilCache	cache.Repository
	// ServiceCache is the service discovery cache
	ServiceCache	cache.Repository

	// Nonce to use when interacting with the dashboard service
	ServiceNonce		string
	ServiceNonceMutex	sync.RWMutex

	apisMu		sync.RWMutex
	apiSpecs	[]*APISpec
	apisByID	map[string]*APISpec
	apisHandlesByID	*sync.Map

	policiesMu	sync.RWMutex
	policiesByID	map[string]user.Policy

	dnsCacheManager	dnscache.IDnsCacheManager

	consulKVStore	kv.Store
	vaultKVStore	kv.Store

	// signatureVerifier is used to verify signatures with config.PublicKeyPath.
	signatureVerifier	atomic.Pointer[goverify.Verifier]

	RedisPurgeOnce	sync.Once
	RpcPurgeOnce	sync.Once

	// OnConnect this is a callback which is called whenever we transition redis Disconnected to connected
	OnConnect	func()

	// SessionID is the unique session id which is used while connecting to dashboard to prevent multiple node allocation.
	SessionID	string

	runningTestsMu	sync.RWMutex
	testMode	bool

	// reloadQueue is used by reloadURLStructure to queue a reload. It's not
	// buffered, as reloadQueueLoop should pick these up immediately.
	reloadQueue	chan func()

	requeueLock	sync.Mutex

	// This is a list of callbacks to execute on the next reload. It is protected by
	// requeueLock for concurrent use.
	requeue	[]func()

	// ReloadTestCase use this when in any test for gateway reloads
	ReloadTestCase	*ReloadMachinery

	// map[bundleName]map[fileName]fileContent used for tests
	TestBundles	map[string]map[string]string
	TestBundleMu	sync.Mutex

	templates	*htmltemplate.Template
	templatesRaw	*texttemplate.Template

	// RedisController keeps track of redis connection and singleton
	StorageConnectionHandler	*storage.ConnectionHandler
	hostDetails			model.HostDetails

	healthCheckInfo	atomic.Value

	dialCtxFn	test.DialContext
}

GetConfigPayload

This type doesn't have documentation.

Field name Field type Comment
FromHostname

string

No comment on field.
FromNodeID

string

No comment on field.
TimeStamp

int64

No comment on field.
type GetConfigPayload struct {
	FromHostname	string
	FromNodeID	string
	TimeStamp	int64
}

GoAnalyticsPlugin

This type doesn't have documentation.

Field name Field type Comment
Path

string

No comment on field.
FuncName

string

No comment on field.
handler

func(record *analytics.AnalyticsRecord)

No comment on field.
logger

*logrus.Entry

No comment on field.
type GoAnalyticsPlugin struct {
	Path		string	// path to .so file
	FuncName	string	// function symbol to look up
	handler		func(record *analytics.AnalyticsRecord)
	logger		*logrus.Entry
}

GoPluginMiddleware

GoPluginMiddleware is a generic middleware that will execute Go-plugin code before continuing

Field name Field type Comment

*BaseMiddleware

No comment on field.
Path

string

No comment on field.
SymbolName

string

No comment on field.
handler

http.HandlerFunc

No comment on field.
logger

*logrus.Entry

No comment on field.
successHandler

*SuccessHandler

No comment on field.
Meta

apidef.GoPluginMeta

No comment on field.
APILevel

bool

No comment on field.
type GoPluginMiddleware struct {
	*BaseMiddleware

	Path		string	// path to .so file
	SymbolName	string	// function symbol to look up
	handler		http.HandlerFunc
	logger		*logrus.Entry
	successHandler	*SuccessHandler	// to record analytics
	Meta		apidef.GoPluginMeta
	APILevel	bool
}

GranularAccessFailReason

This type doesn't have documentation.

Field name Field type Comment
type

int

No comment on field.
type GranularAccessFailReason int

GranularAccessMiddleware

GranularAccessMiddleware will check if a URL is specifically enabled for the key

Field name Field type Comment

*BaseMiddleware

No comment on field.
type GranularAccessMiddleware struct {
	*BaseMiddleware
}

GraphQLComplexityMiddleware

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type GraphQLComplexityMiddleware struct {
	*BaseMiddleware
}

GraphQLGranularAccessMiddleware

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type GraphQLGranularAccessMiddleware struct {
	*BaseMiddleware
}

GraphQLMiddleware

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type GraphQLMiddleware struct {
	*BaseMiddleware
}

GraphQLRequest

This type doesn't have documentation.

Field name Field type Comment
Query

string

No comment on field.
Variables

json.RawMessage

No comment on field.
type GraphQLRequest struct {
	Query		string		`json:"query"`
	Variables	json.RawMessage	`json:"variables"`
}

GraphqlComplexityChecker

This type doesn't have documentation.

Field name Field type Comment
logger

*logrus.Entry

No comment on field.
type GraphqlComplexityChecker struct {
	logger *logrus.Entry
}

GraphqlGranularAccessChecker

This type doesn't have documentation.

type GraphqlGranularAccessChecker struct{}

GraphqlGranularAccessResult

This type doesn't have documentation.

Field name Field type Comment
failReason

GranularAccessFailReason

No comment on field.
validationResult

*graphql.RequestFieldsValidationResult

No comment on field.
internalErr

error

No comment on field.
type GraphqlGranularAccessResult struct {
	failReason		GranularAccessFailReason
	validationResult	*graphql.RequestFieldsValidationResult
	internalErr		error
}

HMACFieldValues

This type doesn't have documentation.

Field name Field type Comment
KeyID

string

No comment on field.
Algorthm

string

No comment on field.
Headers

[]string

No comment on field.
Signature

string

No comment on field.
type HMACFieldValues struct {
	KeyID		string
	Algorthm	string
	Headers		[]string
	Signature	string
}

HTTPBundleGetter

HTTPBundleGetter is a simple HTTP BundleGetter.

Field name Field type Comment
URL

string

No comment on field.
InsecureSkipVerify

bool

No comment on field.
type HTTPBundleGetter struct {
	URL			string
	InsecureSkipVerify	bool
}

HTTPDashboardHandler

This type doesn't have documentation.

Field name Field type Comment
RegistrationEndpoint

string

No comment on field.
DeRegistrationEndpoint

string

No comment on field.
HeartBeatEndpoint

string

No comment on field.
KeyQuotaTriggerEndpoint

string

No comment on field.
Secret

string

No comment on field.
heartBeatStopSentinel

int32

No comment on field.
Gw

*Gateway

No comment on field.
type HTTPDashboardHandler struct {
	RegistrationEndpoint	string
	DeRegistrationEndpoint	string
	HeartBeatEndpoint	string
	KeyQuotaTriggerEndpoint	string

	Secret	string

	heartBeatStopSentinel	int32

	Gw	*Gateway	`json:"-"`
}

HTTPSignatureValidationMiddleware

HTTPSignatureValidationMiddleware will check if the request has a signature, and if the request is allowed through

Field name Field type Comment

*BaseMiddleware

No comment on field.
lowercasePattern

*regexp.Regexp

No comment on field.
type HTTPSignatureValidationMiddleware struct {
	*BaseMiddleware

	lowercasePattern	*regexp.Regexp
}

HeaderInjector

This type doesn't have documentation.

Field name Field type Comment

BaseTykResponseHandler

No comment on field.
config

HeaderInjectorOptions

No comment on field.
type HeaderInjector struct {
	BaseTykResponseHandler
	config	HeaderInjectorOptions
}

HeaderInjectorOptions

This type doesn't have documentation.

Field name Field type Comment
AddHeaders

map[string]string

No comment on field.
RemoveHeaders

[]string

No comment on field.
type HeaderInjectorOptions struct {
	AddHeaders	map[string]string	`mapstructure:"add_headers" bson:"add_headers" json:"add_headers"`
	RemoveHeaders	[]string		`mapstructure:"remove_headers" bson:"remove_headers" json:"remove_headers"`
}

HeaderTransform

This type doesn't have documentation.

Field name Field type Comment

BaseTykResponseHandler

No comment on field.
config

HeaderTransformOptions

No comment on field.
type HeaderTransform struct {
	BaseTykResponseHandler
	config	HeaderTransformOptions
}

HeaderTransformOptions

This type doesn't have documentation.

Field name Field type Comment
RevProxyTransform

RevProxyTransform

No comment on field.
type HeaderTransformOptions struct {
	RevProxyTransform RevProxyTransform `mapstructure:"rev_proxy_header_cleanup" bson:"rev_proxy_header_cleanup" json:"rev_proxy_header_cleanup"`
}

HealthCheckValues

This type doesn't have documentation.

Field name Field type Comment
ThrottledRequestsPS

float64

No comment on field.
QuotaViolationsPS

float64

No comment on field.
KeyFailuresPS

float64

No comment on field.
AvgUpstreamLatency

float64

No comment on field.
AvgRequestsPS

float64

No comment on field.
type HealthCheckValues struct {
	ThrottledRequestsPS	float64	`bson:"throttle_reqests_per_second,omitempty" json:"throttle_reqests_per_second"`
	QuotaViolationsPS	float64	`bson:"quota_violations_per_second,omitempty" json:"quota_violations_per_second"`
	KeyFailuresPS		float64	`bson:"key_failures_per_second,omitempty" json:"key_failures_per_second"`
	AvgUpstreamLatency	float64	`bson:"average_upstream_latency,omitempty" json:"average_upstream_latency"`
	AvgRequestsPS		float64	`bson:"average_requests_per_second,omitempty" json:"average_requests_per_second"`
}

HealthChecker

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type HealthChecker interface {
	Init(storage.Handler)
	ApiHealthValues() (HealthCheckValues, error)
	StoreCounterVal(HealthPrefix, string)
}

HealthPrefix

This type doesn't have documentation.

Field name Field type Comment
type

string

No comment on field.
type HealthPrefix string

HostCheckCallBacks

HostCheckCallBacks defines call backs which will be invoked on different states of the health check

Field name Field type Comment
Up

func(context.Context, HostHealthReport)

Up is a callback invoked when the host checker identifies a host to be up.

Ping

func(context.Context, HostHealthReport)

Ping when provided this callback will be invoked on every every call to a remote host.

Fail

func(context.Context, HostHealthReport)

Fail is invoked when the host checker decides a host is not healthy.

type HostCheckCallBacks struct {
	// Up is a callback invoked when the host checker identifies a host to be up.
	Up	func(context.Context, HostHealthReport)

	// Ping when provided this callback will be invoked on every every call to a
	// remote host.
	Ping	func(context.Context, HostHealthReport)

	// Fail is invoked when the host checker decides a host is not healthy.
	Fail	func(context.Context, HostHealthReport)
}

HostCheckerManager

This type doesn't have documentation.

Field name Field type Comment
Gw

*Gateway

No comment on field.
Id

string

No comment on field.
store

storage.Handler

No comment on field.
checkerMu

sync.Mutex

No comment on field.
checker

*HostUptimeChecker

No comment on field.
stopLoop

bool

No comment on field.
pollerStarted

bool

No comment on field.
unhealthyHostList

*sync.Map

No comment on field.
currentHostList

map[string]HostData

No comment on field.
resetsInitiated

map[string]bool

No comment on field.
type HostCheckerManager struct {
	Gw			*Gateway	`json:"-"`
	Id			string
	store			storage.Handler
	checkerMu		sync.Mutex
	checker			*HostUptimeChecker
	stopLoop		bool
	pollerStarted		bool
	unhealthyHostList	*sync.Map
	currentHostList		map[string]HostData
	resetsInitiated		map[string]bool
}

HostData

This type doesn't have documentation.

Field name Field type Comment
CheckURL

string

No comment on field.
Protocol

string

No comment on field.
Timeout

time.Duration

No comment on field.
EnableProxyProtocol

bool

No comment on field.
Commands

[]apidef.CheckCommand

No comment on field.
Method

string

No comment on field.
Headers

map[string]string

No comment on field.
Body

string

No comment on field.
MetaData

map[string]string

No comment on field.
type HostData struct {
	CheckURL		string
	Protocol		string
	Timeout			time.Duration
	EnableProxyProtocol	bool
	Commands		[]apidef.CheckCommand
	Method			string
	Headers			map[string]string
	Body			string
	MetaData		map[string]string
}

HostHealthReport

This type doesn't have documentation.

Field name Field type Comment

HostData

No comment on field.
ResponseCode

int

No comment on field.
Latency

float64

No comment on field.
IsTCPError

bool

No comment on field.
type HostHealthReport struct {
	HostData
	ResponseCode	int
	Latency		float64
	IsTCPError	bool
}

HostSample

This type doesn't have documentation.

Field name Field type Comment
count

int

No comment on field.
reachedLimit

bool

No comment on field.
type HostSample struct {
	count		int
	reachedLimit	bool
}

HostUptimeChecker

This type doesn't have documentation.

Field name Field type Comment
cb

HostCheckCallBacks

No comment on field.
workerPoolSize

int

No comment on field.
sampleTriggerLimit

int

No comment on field.
checkTimeout

int

No comment on field.
HostList

map[string]HostData

No comment on field.
unHealthyList

map[string]bool

No comment on field.
pool

*tunny.Pool

No comment on field.
errorChan

chan HostHealthReport

No comment on field.
okChan

chan HostHealthReport

No comment on field.
samples

*sync.Map

No comment on field.
stopLoop

bool

No comment on field.
muStopLoop

sync.RWMutex

No comment on field.
resetListMu

sync.Mutex

No comment on field.
doResetList

bool

No comment on field.
newList

map[string]HostData

No comment on field.
Gw

*Gateway

No comment on field.
isClosed

int32

No comment on field.
type HostUptimeChecker struct {
	cb			HostCheckCallBacks
	workerPoolSize		int
	sampleTriggerLimit	int
	checkTimeout		int
	HostList		map[string]HostData
	unHealthyList		map[string]bool
	pool			*tunny.Pool

	errorChan	chan HostHealthReport
	okChan		chan HostHealthReport
	samples		*sync.Map
	stopLoop	bool
	muStopLoop	sync.RWMutex

	resetListMu	sync.Mutex
	doResetList	bool
	newList		map[string]HostData
	Gw		*Gateway	`json:"-"`

	isClosed	int32
}

IPBlackListMiddleware

IPBlackListMiddleware lets you define a list of IPs to block from upstream

Field name Field type Comment

*BaseMiddleware

No comment on field.
type IPBlackListMiddleware struct {
	*BaseMiddleware
}

IPWhiteListMiddleware

IPWhiteListMiddleware lets you define a list of IPs to allow upstream

Field name Field type Comment

*BaseMiddleware

No comment on field.
type IPWhiteListMiddleware struct {
	*BaseMiddleware
}

IdExtractor

IdExtractor is the base interface for an ID extractor.

Field name Field type Comment
type

any

No comment on field.
type IdExtractor interface {
	ExtractAndCheck(*http.Request) (string, ReturnOverrides)
	GenerateSessionID(string, *BaseMiddleware) string
}

InterfaceNotification

This type doesn't have documentation.

Field name Field type Comment
Type

string

No comment on field.
Message

string

No comment on field.
OrgID

string

No comment on field.
Timestamp

time.Time

No comment on field.
type InterfaceNotification struct {
	Type		string
	Message		string
	OrgID		string
	Timestamp	time.Time
}

JSVM

This type doesn't have documentation.

Field name Field type Comment
Spec

*APISpec

No comment on field.
VM

*otto.Otto

No comment on field.
Timeout

time.Duration

No comment on field.
Log

*logrus.Entry

No comment on field.
RawLog

*logrus.Logger

No comment on field.
Gw

*Gateway

No comment on field.
type JSVM struct {
	Spec	*APISpec
	VM	*otto.Otto	`json:"-"`
	Timeout	time.Duration
	Log	*logrus.Entry	`json:"-"`	// logger used by the JS code
	RawLog	*logrus.Logger	`json:"-"`	// logger used by `rawlog` func to avoid formatting
	Gw	*Gateway	`json:"-"`
}

JSVMContextGlobal

This type doesn't have documentation.

Field name Field type Comment
APIID

string

No comment on field.
OrgID

string

No comment on field.
type JSVMContextGlobal struct {
	APIID	string
	OrgID	string
}

JSVMEventHandler

JSVMEventHandler is a scriptable event handler

Field name Field type Comment
conf

apidef.JSVMEventHandlerConf

No comment on field.
Spec

*APISpec

No comment on field.
SpecJSON

string

No comment on field.
Gw

*Gateway

No comment on field.
type JSVMEventHandler struct {
	conf		apidef.JSVMEventHandlerConf
	Spec		*APISpec
	SpecJSON	string
	Gw		*Gateway	`json:"-"`
}

JWK

This type doesn't have documentation.

Field name Field type Comment
Alg

string

No comment on field.
Kty

string

No comment on field.
Use

string

No comment on field.
X5c

[]string

No comment on field.
N

string

No comment on field.
E

string

No comment on field.
KID

string

No comment on field.
X5t

string

No comment on field.
type JWK struct {
	Alg	string		`json:"alg"`
	Kty	string		`json:"kty"`
	Use	string		`json:"use"`
	X5c	[]string	`json:"x5c"`
	N	string		`json:"n"`
	E	string		`json:"e"`
	KID	string		`json:"kid"`
	X5t	string		`json:"x5t"`
}

JWKs

This type doesn't have documentation.

Field name Field type Comment
Keys

[]JWK

No comment on field.
type JWKs struct {
	Keys []JWK `json:"keys"`
}

JWTMiddleware

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type JWTMiddleware struct {
	*BaseMiddleware
}

KeyExpired

KeyExpired middleware will check if the requesting key is expired or not. It makes use of the authManager to do so.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type KeyExpired struct {
	*BaseMiddleware
}

LDAPStorageHandler

LDAPStorageHandler implements storage.Handler, this is a read-only implementation to access keys from an LDAP service

Field name Field type Comment
LDAPServer

string

No comment on field.
LDAPPort

uint16

No comment on field.
BaseDN

string

No comment on field.
Attributes

[]string

No comment on field.
SessionAttributeName

string

No comment on field.
SearchString

string

No comment on field.
store

*ldap.LDAPConnection

No comment on field.
type LDAPStorageHandler struct {
	LDAPServer		string
	LDAPPort		uint16
	BaseDN			string
	Attributes		[]string
	SessionAttributeName	string
	SearchString		string
	store			*ldap.LDAPConnection
}

LogEventMessage

LogEventMessage is an interface that provides a method for formatting log events into a string with a given prefix.

Field name Field type Comment
type

any

No comment on field.
type LogEventMessage interface {
	LogMessage(prefix string) string
}

LogMessageEventHandler

LogMessageEventHandler is a sample Event Handler

Field name Field type Comment
conf

apidef.LogEventHandlerConf

No comment on field.
logger

*logrus.Logger

No comment on field.
Gw

*Gateway

No comment on field.
type LogMessageEventHandler struct {
	conf	apidef.LogEventHandlerConf
	logger	*logrus.Logger
	Gw	*Gateway	`json:"-"`
}

MethodNotAllowedHandler

This type doesn't have documentation.

type MethodNotAllowedHandler struct{}

MiddlewareContextVars

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type MiddlewareContextVars struct {
	*BaseMiddleware
}

MiniRequestObject

MiniRequestObject is marshalled to JSON string and passed into JSON middleware

Field name Field type Comment
Headers

map[string][]string

No comment on field.
SetHeaders

map[string]string

No comment on field.
DeleteHeaders

[]string

No comment on field.
Body

[]byte

No comment on field.
URL

string

No comment on field.
Params

map[string][]string

No comment on field.
AddParams

map[string]string

No comment on field.
ExtendedParams

map[string][]string

No comment on field.
DeleteParams

[]string

No comment on field.
ReturnOverrides

ReturnOverrides

No comment on field.
IgnoreBody

bool

No comment on field.
Method

string

No comment on field.
RequestURI

string

No comment on field.
Scheme

string

No comment on field.
type MiniRequestObject struct {
	Headers		map[string][]string
	SetHeaders	map[string]string
	DeleteHeaders	[]string
	Body		[]byte
	URL		string
	Params		map[string][]string
	AddParams	map[string]string
	ExtendedParams	map[string][]string
	DeleteParams	[]string
	ReturnOverrides	ReturnOverrides
	IgnoreBody	bool
	Method		string
	RequestURI	string
	Scheme		string
}

MockErrorReader

MockErrorReader is a mock io.Reader that returns an error on Read

Field name Field type Comment
ReturnError

error

No comment on field.
type MockErrorReader struct {
	ReturnError error
}

MockReadCloser

This type doesn't have documentation.

Field name Field type Comment
Reader

io.Reader

No comment on field.
CloseError

error

No comment on field.
CloseCalled

bool

No comment on field.
type MockReadCloser struct {
	Reader		io.Reader
	CloseError	error
	CloseCalled	bool
}

Monitor

This type doesn't have documentation.

Field name Field type Comment
Gw

*Gateway

No comment on field.
type Monitor struct {
	Gw *Gateway `json:"-"`
}

MultiTargetProxy

This type doesn't have documentation.

Field name Field type Comment
versionProxies

map[string]*ReverseProxy

No comment on field.
specReference

*APISpec

No comment on field.
defaultProxy

*ReverseProxy

No comment on field.
type MultiTargetProxy struct {
	versionProxies	map[string]*ReverseProxy
	specReference	*APISpec
	defaultProxy	*ReverseProxy
}

NewClientRequest

NewClientRequest is an outward facing JSON object translated from osin OAuthClients

swagger:model NewClientRequest

Field name Field type Comment
ClientID

string

No comment on field.
ClientRedirectURI

string

No comment on field.
APIID

string

No comment on field.
PolicyID

string

No comment on field.
ClientSecret

string

No comment on field.
MetaData

any

No comment on field.
Description

string

No comment on field.
type NewClientRequest struct {
	ClientID		string		`json:"client_id"`
	ClientRedirectURI	string		`json:"redirect_uri"`
	APIID			string		`json:"api_id,omitempty"`
	PolicyID		string		`json:"policy_id,omitempty"`
	ClientSecret		string		`json:"secret"`
	MetaData		interface{}	`json:"meta_data"`
	Description		string		`json:"description"`
}

NewOAuthNotification

NewOAuthNotification is a notification sent to a web-hook when an access request or a refresh request comes in.

Field name Field type Comment
AuthCode

string

No comment on field.
NewOAuthToken

string

No comment on field.
RefreshToken

string

No comment on field.
OldRefreshToken

string

No comment on field.
NotificationType

OAuthNotificationType

No comment on field.
type NewOAuthNotification struct {
	AuthCode		string			`json:"auth_code"`
	NewOAuthToken		string			`json:"new_oauth_token"`
	RefreshToken		string			`json:"refresh_token"`
	OldRefreshToken		string			`json:"old_refresh_token"`
	NotificationType	OAuthNotificationType	`json:"notification_type"`
}

NodeResponseOK

This type doesn't have documentation.

Field name Field type Comment
Status

string

No comment on field.
Message

map[string]string

No comment on field.
Nonce

string

No comment on field.
type NodeResponseOK struct {
	Status	string
	Message	map[string]string
	Nonce	string
}

Notification

Notification is a type that encodes a message published to a pub sub channel (shared between implementations)

Field name Field type Comment
Command

NotificationCommand

No comment on field.
Payload

string

No comment on field.
Signature

string

No comment on field.
SignatureAlgo

crypto.Hash

No comment on field.
Gw

*Gateway

No comment on field.
type Notification struct {
	Command		NotificationCommand	`json:"command"`
	Payload		string			`json:"payload"`
	Signature	string			`json:"signature"`
	SignatureAlgo	crypto.Hash		`json:"algorithm"`
	Gw		*Gateway		`json:"-"`
}

NotificationCommand

This type doesn't have documentation.

Field name Field type Comment
type

string

No comment on field.
type NotificationCommand string

OASSchemaResponse

This type doesn't have documentation.

Field name Field type Comment
Status

string

No comment on field.
Message

string

No comment on field.
Schema

json.RawMessage

No comment on field.
type OASSchemaResponse struct {
	Status	string		`json:"status"`
	Message	string		`json:"message"`
	Schema	json.RawMessage	`json:"schema,omitempty"`
}

OAuthClient

OAuthClient is a representation within an APISpec of a client

Field name Field type Comment
ClientID

string

No comment on field.
ClientSecret

string

No comment on field.
ClientRedirectURI

string

No comment on field.
MetaData

any

No comment on field.
PolicyID

string

No comment on field.
Description

string

No comment on field.
type OAuthClient struct {
	ClientID		string		`json:"id"`
	ClientSecret		string		`json:"secret"`
	ClientRedirectURI	string		`json:"redirecturi"`
	MetaData		interface{}	`json:"meta_data,omitempty"`
	PolicyID		string		`json:"policyid"`
	Description		string		`json:"description"`
}

OAuthClientToken

swagger:model

Field name Field type Comment
Token

string

No comment on field.
Expires

int64

No comment on field.
type OAuthClientToken struct {
	Token	string	`json:"code"`
	Expires	int64	`json:"expires"`
}

OAuthHandlers

OAuthHandlers are the HTTP Handlers that manage the Tyk OAuth flow

Field name Field type Comment
Manager

OAuthManager

No comment on field.
type OAuthHandlers struct {
	Manager OAuthManager
}

OAuthManager

OAuthManager handles and wraps osin OAuth2 functions to handle authorise and access requests

Field name Field type Comment
API

*APISpec

No comment on field.
OsinServer

*TykOsinServer

No comment on field.
Gw

*Gateway

No comment on field.
type OAuthManager struct {
	API		*APISpec
	OsinServer	*TykOsinServer
	Gw		*Gateway	`json:"-"`
}

OAuthManagerInterface

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type OAuthManagerInterface interface {
	Storage() ExtendedOsinStorageInterface
}

OAuthNotificationType

OAuthNotificationType const to reduce risk of collisions

Field name Field type Comment
type

string

No comment on field.
type OAuthNotificationType string

Oauth2KeyExists

Oauth2KeyExists will check if the key being used to access the API is in the request data, and then if the key is in the storage engine

Field name Field type Comment

*BaseMiddleware

No comment on field.
type Oauth2KeyExists struct {
	*BaseMiddleware
}

OpenIDMW

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
providerConfiguration

*openid.Configuration

No comment on field.
provider_client_policymap

map[string]map[string]string

No comment on field.
lock

sync.RWMutex

No comment on field.
type OpenIDMW struct {
	*BaseMiddleware

	providerConfiguration		*openid.Configuration
	provider_client_policymap	map[string]map[string]string
	lock				sync.RWMutex
}

Operation

This type doesn't have documentation.

Field name Field type Comment

*oas.Operation

No comment on field.
route

*routers.Route

No comment on field.
pathParams

map[string]string

No comment on field.
type Operation struct {
	*oas.Operation
	route		*routers.Route
	pathParams	map[string]string
}

OrganizationMonitor

RateLimitAndQuotaCheck will check the incoming request and key whether it is within it's quota and within it's rate limit, it makes use of the SessionLimiter object to do this

Field name Field type Comment

*BaseMiddleware

No comment on field.
sessionlimiter

SessionLimiter

No comment on field.
mon

Monitor

No comment on field.
type OrganizationMonitor struct {
	*BaseMiddleware

	sessionlimiter	SessionLimiter
	mon		Monitor
}

PersistGraphQLOperationMiddleware

PersistGraphQLOperationMiddleware lets you convert any HTTP request into a GraphQL Operation

Field name Field type Comment

*BaseMiddleware

No comment on field.
type PersistGraphQLOperationMiddleware struct {
	*BaseMiddleware
}

PolicyUpdateObj

This type doesn't have documentation.

Field name Field type Comment
Policy

string

No comment on field.
ApplyPolicies

[]string

No comment on field.
type PolicyUpdateObj struct {
	Policy		string		`json:"policy"`
	ApplyPolicies	[]string	`json:"apply_policies"`
}

ProxyResponse

This type doesn't have documentation.

Field name Field type Comment
Response

*http.Response

No comment on field.
UpstreamLatency

time.Duration

UpstreamLatency the time it takes to do roundtrip to upstream. Total time taken for the gateway to receive response from upstream host.

type ProxyResponse struct {
	Response	*http.Response
	// UpstreamLatency the time it takes to do roundtrip to upstream. Total time
	// taken for the gateway to receive response from upstream host.
	UpstreamLatency	time.Duration
}

PublicSession

This type doesn't have documentation.

Field name Field type Comment
Quota

struct { QuotaMax int64 `json:"quota_max"` QuotaRemaining int64 `json:"quota_remaining"` QuotaRenews int64 `json:"quota_renews"` }

No comment on field.
RateLimit

struct { Rate float64 `json:"requests"` Per float64 `json:"per_unit"` }

No comment on field.
type PublicSession struct {
	Quota	struct {
		QuotaMax	int64	`json:"quota_max"`
		QuotaRemaining	int64	`json:"quota_remaining"`
		QuotaRenews	int64	`json:"quota_renews"`
	}	`json:"quota"`
	RateLimit	struct {
		Rate	float64	`json:"requests"`
		Per	float64	`json:"per_unit"`
	}	`json:"rate_limit"`
}

Purger

Purger is an interface that will define how the in-memory store will be purged of analytics data to prevent it growing too large

Field name Field type Comment
type

any

No comment on field.
type Purger interface {
	PurgeCache()
	PurgeLoop(<-chan time.Time)
}

RPCDataLoader

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type RPCDataLoader interface {
	Connect() bool
	GetApiDefinitions(orgId string, tags []string) string
	GetPolicies(orgId string) string
}

RPCStorageHandler

RPCStorageHandler is a storage manager that uses the redis database.

Field name Field type Comment
KeyPrefix

string

No comment on field.
HashKeys

bool

No comment on field.
SuppressRegister

bool

No comment on field.
DoReload

func()

No comment on field.
Gw

*Gateway

No comment on field.
type RPCStorageHandler struct {
	KeyPrefix		string
	HashKeys		bool
	SuppressRegister	bool
	DoReload		func()
	Gw			*Gateway	`json:"-"`
}

RateCheckMW

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type RateCheckMW struct {
	*BaseMiddleware
}

RateLimitAndQuotaCheck

RateLimitAndQuotaCheck will check the incomming request and key whether it is within it's quota and within it's rate limit, it makes use of the SessionLimiter object to do this

Field name Field type Comment

*BaseMiddleware

No comment on field.
type RateLimitAndQuotaCheck struct {
	*BaseMiddleware
}

RateLimitForAPI

RateLimitAndQuotaCheck will check the incoming request and key whether it is within it's quota and within it's rate limit, it makes use of the SessionLimiter object to do this

Field name Field type Comment

*BaseMiddleware

No comment on field.
keyName

string

No comment on field.
apiSess

*user.SessionState

No comment on field.
type RateLimitForAPI struct {
	*BaseMiddleware

	keyName	string
	apiSess	*user.SessionState
}

RedisAnalyticsHandler

RedisAnalyticsHandler will record analytics data to a redis back end as defined in the Config object

Field name Field type Comment
Store

storage.AnalyticsHandler

No comment on field.
GeoIPDB

*maxminddb.Reader

No comment on field.
globalConf

config.Config

No comment on field.
recordsChan

chan *analytics.AnalyticsRecord

No comment on field.
workerBufferSize

uint64

No comment on field.
shouldStop

uint32

No comment on field.
poolWg

sync.WaitGroup

No comment on field.
enableMultipleAnalyticsKeys

bool

No comment on field.
Clean

Purger

No comment on field.
Gw

*Gateway

No comment on field.
mu

sync.Mutex

No comment on field.
analyticsSerializer

serializer.AnalyticsSerializer

No comment on field.
mockEnabled

bool

testing purposes

mockRecordHit

func(record *analytics.AnalyticsRecord)

No comment on field.
type RedisAnalyticsHandler struct {
	Store				storage.AnalyticsHandler
	GeoIPDB				*maxminddb.Reader
	globalConf			config.Config
	recordsChan			chan *analytics.AnalyticsRecord
	workerBufferSize		uint64
	shouldStop			uint32
	poolWg				sync.WaitGroup
	enableMultipleAnalyticsKeys	bool
	Clean				Purger
	Gw				*Gateway	`json:"-"`
	mu				sync.Mutex
	analyticsSerializer		serializer.AnalyticsSerializer

	// testing purposes
	mockEnabled	bool
	mockRecordHit	func(record *analytics.AnalyticsRecord)
}

RedisCacheMiddleware

RedisCacheMiddleware is a caching middleware that will pull data from Redis instead of the upstream proxy

Field name Field type Comment

*BaseMiddleware

No comment on field.
store

storage.Handler

No comment on field.
sh

SuccessHandler

No comment on field.
type RedisCacheMiddleware struct {
	*BaseMiddleware

	store	storage.Handler
	sh	SuccessHandler
}

RedisNotifier

RedisNotifier will use redis pub/sub channels to send notifications

Field name Field type Comment
store

*storage.RedisCluster

No comment on field.
channel

string

No comment on field.

*Gateway

No comment on field.
type RedisNotifier struct {
	store	*storage.RedisCluster
	channel	string
	*Gateway
}

RedisOsinStorageInterface

TODO: Refactor this to move prefix handling into a checker method, then it can be an unexported setting in the struct. RedisOsinStorageInterface implements osin.Storage interface to use Tyk's own storage mechanism

Field name Field type Comment
store

storage.Handler

No comment on field.
sessionManager

SessionHandler

No comment on field.
redisStore

storage.Handler

No comment on field.
orgID

string

No comment on field.
Gw

*Gateway

No comment on field.
type RedisOsinStorageInterface struct {
	store		storage.Handler
	sessionManager	SessionHandler
	redisStore	storage.Handler
	orgID		string
	Gw		*Gateway	`json:"-"`
}

RedisPurger

This type doesn't have documentation.

Field name Field type Comment
Store

storage.Handler

No comment on field.
Gw

*Gateway

No comment on field.
type RedisPurger struct {
	Store	storage.Handler
	Gw	*Gateway	`json:"-"`
}

RegexExtractor

This type doesn't have documentation.

Field name Field type Comment

BaseExtractor

No comment on field.
compiledExpr

*regexp.Regexp

No comment on field.
type RegexExtractor struct {
	BaseExtractor
	compiledExpr	*regexp.Regexp
}

ReloadMachinery

ReloadMachinery is a helper struct to use when writing tests that do manual gateway reloads

Field name Field type Comment
run

bool

No comment on field.
count

int

No comment on field.
cycles

int

No comment on field.
mu

sync.RWMutex

No comment on field.
reloadTick

chan time.Time

to simulate time ticks for tests that do reloads

stop

chan struct{}

No comment on field.
started

bool

No comment on field.
type ReloadMachinery struct {
	run	bool
	count	int
	cycles	int
	mu	sync.RWMutex

	// to simulate time ticks for tests that do reloads
	reloadTick	chan time.Time
	stop		chan struct{}
	started		bool
}

RequestDefinition

RequestDefinition defines a batch request

Field name Field type Comment
Method

string

No comment on field.
Headers

map[string]string

No comment on field.
Body

string

No comment on field.
RelativeURL

string

No comment on field.
type RequestDefinition struct {
	Method		string			`json:"method"`
	Headers		map[string]string	`json:"headers"`
	Body		string			`json:"body"`
	RelativeURL	string			`json:"relative_url"`
}

RequestObject

RequestObject is marshalled to JSON string and passed into JSON middleware

Field name Field type Comment
Headers

map[string][]string

No comment on field.
Body

string

No comment on field.
URL

string

No comment on field.
Params

map[string][]string

No comment on field.
Scheme

string

No comment on field.
type RequestObject struct {
	Headers	map[string][]string
	Body	string
	URL	string
	Params	map[string][]string
	Scheme	string
}

RequestSigning

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type RequestSigning struct {
	*BaseMiddleware
}

RequestSizeLimitMiddleware

RequestSizeLimitMiddleware is a middleware that will enforce a limit on the request body size. The request has already been copied to memory when this middleware is called. Therefore, this middleware can't protect the gateway itself from large requests.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type RequestSizeLimitMiddleware struct {
	*BaseMiddleware
}

RequestStatus

RequestStatus is a custom type to avoid collisions

Field name Field type Comment
type

string

No comment on field.
type RequestStatus string

ResponseCacheMiddleware

ResponseCacheMiddleware is a caching middleware that will pull data from Redis instead of the upstream proxy

Field name Field type Comment

BaseTykResponseHandler

No comment on field.
store

storage.Handler

No comment on field.
type ResponseCacheMiddleware struct {
	BaseTykResponseHandler
	store	storage.Handler
}

ResponseGoPluginMiddleware

This type doesn't have documentation.

Field name Field type Comment

BaseTykResponseHandler

No comment on field.
Path

string

No comment on field.
SymbolName

string

No comment on field.
logger

*logrus.Entry

No comment on field.
ResHandler

func(rw http.ResponseWriter, res *http.Response, req *http.Request)

No comment on field.
type ResponseGoPluginMiddleware struct {
	BaseTykResponseHandler
	Path		string	// path to .so file
	SymbolName	string	// function symbol to look up
	logger		*logrus.Entry
	ResHandler	func(rw http.ResponseWriter, res *http.Response, req *http.Request)
}

ResponseObject

This type doesn't have documentation.

Field name Field type Comment
Body

string

No comment on field.
Headers

map[string]string

No comment on field.
Code

int

No comment on field.
type ResponseObject struct {
	Body	string
	Headers	map[string]string
	Code	int
}

ResponseTransformJQMiddleware

This type doesn't have documentation.

Field name Field type Comment

BaseTykResponseHandler

No comment on field.
type ResponseTransformJQMiddleware struct {
	BaseTykResponseHandler
}

ResponseTransformMiddleware

This type doesn't have documentation.

Field name Field type Comment

BaseTykResponseHandler

No comment on field.
type ResponseTransformMiddleware struct {
	BaseTykResponseHandler
}

ReturnConfigPayload

This type doesn't have documentation.

Field name Field type Comment
FromHostname

string

No comment on field.
FromNodeID

string

No comment on field.
Configuration

map[string]any

No comment on field.
TimeStamp

int64

No comment on field.
type ReturnConfigPayload struct {
	FromHostname	string
	FromNodeID	string
	Configuration	map[string]interface{}
	TimeStamp	int64
}

ReturnOverrides

Lets the user override and return a response from middleware

Field name Field type Comment
ResponseCode

int

No comment on field.
ResponseError

string

No comment on field.
ResponseBody

string

No comment on field.
ResponseHeaders

map[string]string

No comment on field.
OverrideError

bool

No comment on field.
type ReturnOverrides struct {
	ResponseCode	int
	ResponseError	string
	ResponseBody	string
	ResponseHeaders	map[string]string
	OverrideError	bool
}

ReturningHttpHandler

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type ReturningHttpHandler interface {
	ServeHTTP(http.ResponseWriter, *http.Request) ProxyResponse
	ServeHTTPForCache(http.ResponseWriter, *http.Request) ProxyResponse
	CopyResponse(io.Writer, io.Reader, time.Duration)
}

RevProxyTransform

This type doesn't have documentation.

Field name Field type Comment
Headers

[]string

No comment on field.
Target_host

string

No comment on field.
type RevProxyTransform struct {
	Headers		[]string	// List of HTTP headers to be modified
	Target_host	string		// Target host for reverse proxy
}

ReverseProxy

ReverseProxy is an HTTP Handler that takes an incoming request and sends it to another server, proxying the response back to the client.

Field name Field type Comment
Director

func(*http.Request)

Director must be a function which modifies the request into a new request to be sent using Transport. Its response is then copied back to the original client unmodified.

Transport

http.RoundTripper

The transport used to perform proxy requests. If nil, http.DefaultTransport is used.

FlushInterval

time.Duration

FlushInterval specifies the flush interval to flush to the client while copying the response body. If zero, no periodic flushing is done.

TLSClientConfig

*tls.Config

TLSClientConfig specifies the TLS configuration to use for 'wss'. If nil, the default configuration is used.

wsUpgrader

websocket.Upgrader

wsUpgrader takes care of upgrading the incoming connection to a websocket connection.

TykAPISpec

*APISpec

No comment on field.
ErrorHandler

ErrorHandler

No comment on field.
logger

*logrus.Entry

No comment on field.
sp

sync.Pool

No comment on field.
Gw

*Gateway

No comment on field.
type ReverseProxy struct {
	// Director must be a function which modifies
	// the request into a new request to be sent
	// using Transport. Its response is then copied
	// back to the original client unmodified.
	Director	func(*http.Request)

	// The transport used to perform proxy requests.
	// If nil, http.DefaultTransport is used.
	Transport	http.RoundTripper

	// FlushInterval specifies the flush interval
	// to flush to the client while copying the
	// response body.
	// If zero, no periodic flushing is done.
	FlushInterval	time.Duration

	// TLSClientConfig specifies the TLS configuration to use for 'wss'.
	// If nil, the default configuration is used.
	TLSClientConfig	*tls.Config

	// wsUpgrader takes care of upgrading the incoming connection
	// to a websocket connection.
	wsUpgrader	websocket.Upgrader

	TykAPISpec	*APISpec
	ErrorHandler	ErrorHandler

	logger	*logrus.Entry
	sp	sync.Pool
	Gw	*Gateway	`json:"-"`
}

RoundRobin

This type doesn't have documentation.

Field name Field type Comment
pos

uint32

No comment on field.
type RoundRobin struct {
	pos uint32
}

SafeHealthCheck

This type doesn't have documentation.

Field name Field type Comment
info

map[string]HealthCheckItem

No comment on field.
mux

sync.Mutex

No comment on field.
type SafeHealthCheck struct {
	info	map[string]HealthCheckItem
	mux	sync.Mutex
}

ServiceDiscovery

This type doesn't have documentation.

Field name Field type Comment
spec

*apidef.ServiceDiscoveryConfiguration

No comment on field.
isNested

bool

No comment on field.
isTargetList

bool

No comment on field.
endpointReturnsList

bool

No comment on field.
portSeperate

bool

No comment on field.
dataPath

string

No comment on field.
parentPath

string

No comment on field.
portPath

string

No comment on field.
targetPath

string

No comment on field.
type ServiceDiscovery struct {
	spec			*apidef.ServiceDiscoveryConfiguration
	isNested		bool
	isTargetList		bool
	endpointReturnsList	bool
	portSeperate		bool
	dataPath		string
	parentPath		string
	portPath		string
	targetPath		string
}

SessionHandler

SessionHandler handles all update/create/access session functions and deals exclusively with user.SessionState objects, not identity

Field name Field type Comment
type

any

No comment on field.
type SessionHandler interface {
	Init(store storage.Handler)
	Store() storage.Handler
	UpdateSession(keyName string, session *user.SessionState, resetTTLTo int64, hashed bool) error
	RemoveSession(orgID string, keyName string, hashed bool) bool
	SessionDetail(orgID string, keyName string, hashed bool) (user.SessionState, bool)
	KeyExpired(newSession *user.SessionState) bool
	Sessions(filter string) []string
	ResetQuota(string, *user.SessionState, bool)
	Stop()
}

SessionLimiter

SessionLimiter is the rate limiter for the API, use ForwardMessage() to check if a message should pass through or not

Field name Field type Comment
ctx

context.Context

No comment on field.
drlManager

*drl.DRL

No comment on field.
config

*config.Config

No comment on field.
bucketStore

model.BucketStorage

No comment on field.
limiterStorage

redis.UniversalClient

No comment on field.
smoothing

*rate.Smoothing

No comment on field.
type SessionLimiter struct {
	ctx		context.Context
	drlManager	*drl.DRL
	config		*config.Config
	bucketStore	model.BucketStorage
	limiterStorage	redis.UniversalClient
	smoothing	*rate.Smoothing
}

SlaveDataCenter

This type doesn't have documentation.

Field name Field type Comment
SlaveOptions

config.SlaveOptionsConfig

No comment on field.
Redis

config.StorageOptionsConf

No comment on field.
type SlaveDataCenter struct {
	SlaveOptions	config.SlaveOptionsConfig
	Redis		config.StorageOptionsConf
}

StatsDSink

This type doesn't have documentation.

Field name Field type Comment
options

StatsDSinkOptions

No comment on field.
cmdChan

chan statsdEmitCmd

No comment on field.
drainDoneChan

chan struct{}

No comment on field.
stopDoneChan

chan struct{}

No comment on field.
flushPeriod

time.Duration

No comment on field.
udpBuf

bytes.Buffer

No comment on field.
timingBuf

[]byte

No comment on field.
udpConn

*net.UDPConn

No comment on field.
udpAddr

*net.UDPAddr

No comment on field.
prefixBuffers

map[eventKey]prefixBuffer

map of {job,event,suffix} to a re-usable buffer prefixed with the key. Since each timing/gauge has a unique component (the time), we'll truncate to the prefix, write the timing, and write the statsD suffix (eg, "|ms\n"). Then copy that to the UDP buffer.

type StatsDSink struct {
	options	StatsDSinkOptions

	cmdChan		chan statsdEmitCmd
	drainDoneChan	chan struct{}
	stopDoneChan	chan struct{}

	flushPeriod	time.Duration

	udpBuf		bytes.Buffer
	timingBuf	[]byte

	udpConn	*net.UDPConn
	udpAddr	*net.UDPAddr

	// map of {job,event,suffix} to a re-usable buffer prefixed with the key.
	// Since each timing/gauge has a unique component (the time), we'll truncate to the prefix, write the timing,
	// and write the statsD suffix (eg, "|ms\n"). Then copy that to the UDP buffer.
	prefixBuffers	map[eventKey]prefixBuffer
}

StatsDSinkOptions

This type doesn't have documentation.

Field name Field type Comment
Prefix

string

Prefix is something like "metroid" Events emitted to StatsD would be metroid.myevent.wat Eg, don't include a trailing dot in the prefix. It can be "", that's fine.

SanitizationFunc

StatsDSinkSanitizationFunc

SanitizationFunc sanitizes jobs and events before sending them to statsd

SkipNestedEvents

bool

SkipNestedEvents will skip {events,timers,gauges} from sending the job.event version and will only send the event version.

SkipTopLevelEvents

bool

SkipTopLevelEvents will skip {events,timers,gauges} from sending the event version and will only send the job.event version.

type StatsDSinkOptions struct {
	// Prefix is something like "metroid"
	// Events emitted to StatsD would be metroid.myevent.wat
	// Eg, don't include a trailing dot in the prefix.
	// It can be "", that's fine.
	Prefix	string

	// SanitizationFunc sanitizes jobs and events before sending them to statsd
	SanitizationFunc	StatsDSinkSanitizationFunc

	// SkipNestedEvents will skip {events,timers,gauges} from sending the job.event version
	// and will only send the event version.
	SkipNestedEvents	bool

	// SkipTopLevelEvents will skip {events,timers,gauges} from sending the event version
	// and will only send the job.event version.
	SkipTopLevelEvents	bool
}

StatsDSinkSanitizationFunc

This type doesn't have documentation.

Field name Field type Comment
type

func(*bytes.Buffer, string)

No comment on field.
type StatsDSinkSanitizationFunc func(*bytes.Buffer, string)

StripAuth

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type StripAuth struct {
	*BaseMiddleware
}

SuccessHandler

SuccessHandler represents the final ServeHTTP() request for a proxied API request

Field name Field type Comment

*BaseMiddleware

No comment on field.
type SuccessHandler struct {
	*BaseMiddleware
}

TemplateExecutor

TemplateExecutor is an interface used to switch between text/templates and html/template. It only switch to text/template (templatesRaw) when contentType is XML related

Field name Field type Comment
type

any

No comment on field.
type TemplateExecutor interface {
	Execute(wr io.Writer, data interface{}) error
}

Test

This type doesn't have documentation.

Field name Field type Comment
URL

string

No comment on field.
testRunner

*test.HTTPTestRunner

No comment on field.
GlobalConfig

config.Config

GlobalConfig deprecate this and instead use GW.getConfig()

config

TestConfig

No comment on field.
Gw

*Gateway

No comment on field.
HttpHandler

*http.Server

No comment on field.
TestServerRouter

*mux.Router

No comment on field.
MockHandle

*test.DnsMockHandle

No comment on field.
ctx

context.Context

No comment on field.
cancel

context.CancelFunc

No comment on field.
dynamicHandlers

map[string]http.HandlerFunc

No comment on field.
type Test struct {
	URL		string
	testRunner	*test.HTTPTestRunner
	// GlobalConfig deprecate this and instead use GW.getConfig()
	GlobalConfig		config.Config
	config			TestConfig
	Gw			*Gateway	`json:"-"`
	HttpHandler		*http.Server
	TestServerRouter	*mux.Router
	MockHandle		*test.DnsMockHandle

	ctx	context.Context
	cancel	context.CancelFunc

	dynamicHandlers	map[string]http.HandlerFunc
}

TestConfig

This type doesn't have documentation.

Field name Field type Comment
SeparateControlAPI

bool

No comment on field.
Delay

time.Duration

No comment on field.
HotReload

bool

No comment on field.
overrideDefaults

bool

No comment on field.
CoprocessConfig

config.CoProcessConfig

No comment on field.
EnableTestDNSMock

bool

No comment on field.
type TestConfig struct {
	SeparateControlAPI	bool
	Delay			time.Duration
	HotReload		bool
	overrideDefaults	bool
	CoprocessConfig		config.CoProcessConfig
	EnableTestDNSMock	bool
}

TestHttpResponse

This type doesn't have documentation.

Field name Field type Comment
Method

string

No comment on field.
URI

string

No comment on field.
Path

string

No comment on field.
Url

string

No comment on field.
Body

string

No comment on field.
Headers

map[string]string

No comment on field.
Form

map[string]string

No comment on field.
type TestHttpResponse struct {
	Method	string
	URI	string
	Path	string
	Url	string
	Body	string
	Headers	map[string]string
	Form	map[string]string
}

TraceMiddleware

This type doesn't have documentation.

Field name Field type Comment

TykMiddleware

No comment on field.
type TraceMiddleware struct {
	TykMiddleware
}

TrackEndpointMiddleware

TrackEndpointMiddleware sets context variables to enable or disable whether Tyk should record analytitcs for a specific path.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type TrackEndpointMiddleware struct {
	*BaseMiddleware
}

TransformHeaders

TransformMiddleware is a middleware that will apply a template to a request body to transform it's contents ready for an upstream API

Field name Field type Comment

*BaseMiddleware

No comment on field.
type TransformHeaders struct {
	*BaseMiddleware
}

TransformJQMiddleware

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type TransformJQMiddleware struct {
	*BaseMiddleware
}

TransformJQSpec

This type doesn't have documentation.

Field name Field type Comment

apidef.TransformJQMeta

No comment on field.
type TransformJQSpec struct {
	apidef.TransformJQMeta
}

TransformMethod

TransformMiddleware is a middleware that will apply a template to a request body to transform it's contents ready for an upstream API

Field name Field type Comment

*BaseMiddleware

No comment on field.
type TransformMethod struct {
	*BaseMiddleware
}

TransformMiddleware

TransformMiddleware is a middleware that will apply a template to a request body to transform it's contents ready for an upstream API

Field name Field type Comment

*BaseMiddleware

No comment on field.
type TransformMiddleware struct {
	*BaseMiddleware
}

TransformSpec

This type doesn't have documentation.

Field name Field type Comment

apidef.TemplateMeta

No comment on field.
Template

*texttemplate.Template

No comment on field.
type TransformSpec struct {
	apidef.TemplateMeta
	Template	*texttemplate.Template
}

TykGoPluginResponseHandler

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type TykGoPluginResponseHandler interface {
	TykResponseHandler
	HandleGoPluginResponse(http.ResponseWriter, *http.Response, *http.Request) error
}

TykJSHttpRequest

This type doesn't have documentation.

Field name Field type Comment
Method

string

No comment on field.
Body

string

No comment on field.
Headers

map[string]string

No comment on field.
Domain

string

No comment on field.
Resource

string

No comment on field.
FormData

map[string]string

No comment on field.
type TykJSHttpRequest struct {
	Method		string
	Body		string
	Headers		map[string]string
	Domain		string
	Resource	string
	FormData	map[string]string
}

TykJSHttpResponse

This type doesn't have documentation.

Field name Field type Comment
Code

int

No comment on field.
Body

string

No comment on field.
Headers

map[string][]string

No comment on field.
CodeComp

int

Make this compatible with BatchReplyUnit

BodyComp

string

No comment on field.
HeadersComp

map[string][]string

No comment on field.
type TykJSHttpResponse struct {
	Code	int
	Body	string
	Headers	map[string][]string

	// Make this compatible with BatchReplyUnit
	CodeComp	int			`json:"code"`
	BodyComp	string			`json:"body"`
	HeadersComp	map[string][]string	`json:"headers"`
}

TykMiddleware

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type TykMiddleware interface {
	Base() *BaseMiddleware
	GetSpec() *APISpec

	Init()
	Logger() *logrus.Entry
	Config() (interface{}, error)
	ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (error, int)	// Handles request
	EnabledForSpec() bool
	Name() string

	Unload()
}

TykOsinServer

TykOsinServer subclasses osin.Server so we can add the SetClient method without wrecking the lbrary

Field name Field type Comment

osin.Server

No comment on field.
Config

*osin.ServerConfig

No comment on field.
Storage

ExtendedOsinStorageInterface

No comment on field.
AuthorizeTokenGen

osin.AuthorizeTokenGen

No comment on field.
AccessTokenGen

osin.AccessTokenGen

No comment on field.
type TykOsinServer struct {
	osin.Server
	Config			*osin.ServerConfig
	Storage			ExtendedOsinStorageInterface
	AuthorizeTokenGen	osin.AuthorizeTokenGen
	AccessTokenGen		osin.AccessTokenGen
}

TykResponseHandler

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type TykResponseHandler interface {
	Enabled() bool
	Init(interface{}, *APISpec) error
	Name() string
	HandleResponse(http.ResponseWriter, *http.Response, *http.Request, *user.SessionState) error
	HandleError(http.ResponseWriter, *http.Request)
	Base() *BaseTykResponseHandler
}

TykRoundTripper

This type doesn't have documentation.

Field name Field type Comment
transport

*http.Transport

No comment on field.
h2ctransport

*http2.Transport

No comment on field.
logger

*logrus.Entry

No comment on field.
Gw

*Gateway

No comment on field.
type TykRoundTripper struct {
	transport	*http.Transport
	h2ctransport	*http2.Transport
	logger		*logrus.Entry
	Gw		*Gateway	`json:"-"`
}

URLRewriteMiddleware

URLRewriteMiddleware Will rewrite an inbund URL to a matching outbound one, it can also handle dynamic variable substitution

Field name Field type Comment

*BaseMiddleware

No comment on field.
type URLRewriteMiddleware struct {
	*BaseMiddleware
}

URLSpec

URLSpec represents a flattened specification for URLs, used to check if a proxy URL path is on any of the white, black or ignored lists. This is generated as part of the configuration init

Field name Field type Comment
spec

*regexp.Regexp

No comment on field.
Status

URLStatus

No comment on field.
MethodActions

map[string]apidef.EndpointMethodMeta

No comment on field.
Whitelist

apidef.EndPointMeta

No comment on field.
Blacklist

apidef.EndPointMeta

No comment on field.
Ignored

apidef.EndPointMeta

No comment on field.
MockResponse

apidef.MockResponseMeta

No comment on field.
CacheConfig

EndPointCacheMeta

No comment on field.
TransformAction

TransformSpec

No comment on field.
TransformResponseAction

TransformSpec

No comment on field.
TransformJQAction

TransformJQSpec

No comment on field.
TransformJQResponseAction

TransformJQSpec

No comment on field.
InjectHeaders

apidef.HeaderInjectionMeta

No comment on field.
InjectHeadersResponse

apidef.HeaderInjectionMeta

No comment on field.
HardTimeout

apidef.HardTimeoutMeta

No comment on field.
CircuitBreaker

ExtendedCircuitBreakerMeta

No comment on field.
URLRewrite

*apidef.URLRewriteMeta

No comment on field.
VirtualPathSpec

apidef.VirtualMeta

No comment on field.
RequestSize

apidef.RequestSizeMeta

No comment on field.
MethodTransform

apidef.MethodTransformMeta

No comment on field.
TrackEndpoint

apidef.TrackEndpointMeta

No comment on field.
DoNotTrackEndpoint

apidef.TrackEndpointMeta

No comment on field.
ValidatePathMeta

apidef.ValidatePathMeta

No comment on field.
Internal

apidef.InternalMeta

No comment on field.
GoPluginMeta

GoPluginMiddleware

No comment on field.
PersistGraphQL

apidef.PersistGraphQLMeta

No comment on field.
RateLimit

apidef.RateLimitMeta

No comment on field.
IgnoreCase

bool

No comment on field.
type URLSpec struct {
	spec	*regexp.Regexp

	Status				URLStatus
	MethodActions			map[string]apidef.EndpointMethodMeta
	Whitelist			apidef.EndPointMeta
	Blacklist			apidef.EndPointMeta
	Ignored				apidef.EndPointMeta
	MockResponse			apidef.MockResponseMeta
	CacheConfig			EndPointCacheMeta
	TransformAction			TransformSpec
	TransformResponseAction		TransformSpec
	TransformJQAction		TransformJQSpec
	TransformJQResponseAction	TransformJQSpec
	InjectHeaders			apidef.HeaderInjectionMeta
	InjectHeadersResponse		apidef.HeaderInjectionMeta
	HardTimeout			apidef.HardTimeoutMeta
	CircuitBreaker			ExtendedCircuitBreakerMeta
	URLRewrite			*apidef.URLRewriteMeta
	VirtualPathSpec			apidef.VirtualMeta
	RequestSize			apidef.RequestSizeMeta
	MethodTransform			apidef.MethodTransformMeta
	TrackEndpoint			apidef.TrackEndpointMeta
	DoNotTrackEndpoint		apidef.TrackEndpointMeta
	ValidatePathMeta		apidef.ValidatePathMeta
	Internal			apidef.InternalMeta
	GoPluginMeta			GoPluginMiddleware
	PersistGraphQL			apidef.PersistGraphQLMeta
	RateLimit			apidef.RateLimitMeta

	IgnoreCase	bool
}

URLStatus

URLStatus is a custom enum type to avoid collisions

Field name Field type Comment
type

int

No comment on field.
type URLStatus int

UptimeReportData

This type doesn't have documentation.

Field name Field type Comment
URL

string

No comment on field.
RequestTime

int64

No comment on field.
ResponseCode

int

No comment on field.
TCPError

bool

No comment on field.
ServerError

bool

No comment on field.
Day

int

No comment on field.
Month

time.Month

No comment on field.
Year

int

No comment on field.
Hour

int

No comment on field.
Minute

int

No comment on field.
TimeStamp

time.Time

No comment on field.
ExpireAt

time.Time

No comment on field.
APIID

string

No comment on field.
OrgID

string

No comment on field.
type UptimeReportData struct {
	URL		string
	RequestTime	int64
	ResponseCode	int
	TCPError	bool
	ServerError	bool
	Day		int
	Month		time.Month
	Year		int
	Hour		int
	Minute		int
	TimeStamp	time.Time
	ExpireAt	time.Time	`bson:"expireAt" json:"expireAt"`
	APIID		string
	OrgID		string
}

VMResponseObject

This type doesn't have documentation.

Field name Field type Comment
Response

ResponseObject

No comment on field.
SessionMeta

map[string]any

No comment on field.
type VMResponseObject struct {
	Response	ResponseObject
	SessionMeta	map[string]interface{}
}

VMReturnObject

This type doesn't have documentation.

Field name Field type Comment
Request

MiniRequestObject

No comment on field.
SessionMeta

map[string]string

No comment on field.
Session

user.SessionState

No comment on field.
AuthValue

string

No comment on field.
type VMReturnObject struct {
	Request		MiniRequestObject
	SessionMeta	map[string]string
	Session		user.SessionState
	AuthValue	string
}

ValidateJSON

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type ValidateJSON struct {
	*BaseMiddleware
}

ValidateRequest

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type ValidateRequest struct {
	*BaseMiddleware
}

ValueExtractor

This type doesn't have documentation.

Field name Field type Comment

BaseExtractor

No comment on field.
type ValueExtractor struct {
	BaseExtractor
}

VersionCheck

VersionCheck will check whether the version of the requested API the request is accessing has any restrictions on URL endpoints

Field name Field type Comment

*BaseMiddleware

No comment on field.
sh

SuccessHandler

No comment on field.
type VersionCheck struct {
	*BaseMiddleware

	sh	SuccessHandler
}

VersionMeta

This type doesn't have documentation.

Field name Field type Comment
ID

string

No comment on field.
Name

string

No comment on field.
VersionName

string

No comment on field.
Internal

bool

No comment on field.
ExpirationDate

string

No comment on field.
IsDefaultVersion

bool

No comment on field.
type VersionMeta struct {
	ID			string	`json:"id"`
	Name			string	`json:"name"`
	VersionName		string	`json:"versionName"`
	Internal		bool	`json:"internal"`
	ExpirationDate		string	`json:"expirationDate"`
	IsDefaultVersion	bool	`json:"isDefaultVersion"`
}

VersionMetas

This type doesn't have documentation.

Field name Field type Comment
Status

string

No comment on field.
Metas

[]VersionMeta

No comment on field.
type VersionMetas struct {
	Status	string		`json:"status"`
	Metas	[]VersionMeta	`json:"apis"`
}

VersionsHandler

This type doesn't have documentation.

Field name Field type Comment
getApiDef

func(string) (*apidef.APIDefinition, error)

No comment on field.
type VersionsHandler struct {
	getApiDef func(string) (*apidef.APIDefinition, error)
}

VirtualEndpoint

DynamicMiddleware is a generic middleware that will execute JS code before continuing

Field name Field type Comment

*BaseMiddleware

No comment on field.
sh

SuccessHandler

No comment on field.
type VirtualEndpoint struct {
	*BaseMiddleware

	sh	SuccessHandler
}

WebHookHandler

WebHookHandler is an event handler that triggers web hooks

Field name Field type Comment
conf

apidef.WebHookHandlerConf

No comment on field.
template

*htmltemplate.Template

No comment on field.
store

storage.Handler

No comment on field.
contentType

string

No comment on field.
dashboardService

DashboardServiceSender

No comment on field.
Gw

*Gateway

No comment on field.
type WebHookHandler struct {
	conf		apidef.WebHookHandlerConf
	template	*htmltemplate.Template	// non-nil if Init is run without error
	store		storage.Handler

	contentType		string
	dashboardService	DashboardServiceSender
	Gw			*Gateway
}

WebHookRequestMethod

This type doesn't have documentation.

Field name Field type Comment
type

string

No comment on field.
type WebHookRequestMethod string

XPathExtractor

This type doesn't have documentation.

Field name Field type Comment

BaseExtractor

No comment on field.
path

*xmlpath.Path

No comment on field.
type XPathExtractor struct {
	BaseExtractor
	path	*xmlpath.Path
}

ZipBundleSaver

ZipBundleSaver is a BundleSaver for ZIP files.

type ZipBundleSaver struct{}

HealthCheckItem, HealthCheckStatus, HealthCheckResponse

This type doesn't have documentation.

Field name Field type Comment
type

model.HealthCheckItem

No comment on field.
type

model.HealthCheckStatus

No comment on field.
type

model.HealthCheckResponse

No comment on field.
type (
	HealthCheckItem		= model.HealthCheckItem
	HealthCheckStatus	= model.HealthCheckStatus
	HealthCheckResponse	= model.HealthCheckResponse
)

accessTokenGen

accessTokenGen is a modified authorization token generator that uses the same method used to generate tokens for Tyk authHandler

Field name Field type Comment
Gw

*Gateway

No comment on field.
type accessTokenGen struct {
	Gw *Gateway `json:"-"`
}

apiAllKeys

apiAllKeys represents a list of keys in the memory store swagger:model

Field name Field type Comment
APIKeys

[]string

No comment on field.
type apiAllKeys struct {
	APIKeys []string `json:"keys"`
}

apiModifyKeySuccess

apiModifyKeySuccess represents when a Key modification was successful

swagger:model apiModifyKeySuccess

Field name Field type Comment
Key

string

in:body

Status

string

No comment on field.
Action

string

No comment on field.
KeyHash

string

No comment on field.
type apiModifyKeySuccess struct {
	// in:body
	Key	string	`json:"key"`
	Status	string	`json:"status"`
	Action	string	`json:"action"`
	KeyHash	string	`json:"key_hash,omitempty"`
}

apiStatusMessage

apiStatusMessage represents an API status message

swagger:model apiStatusMessage

Field name Field type Comment
Status

string

No comment on field.
Message

string

Response details

type apiStatusMessage struct {
	Status	string	`json:"status"`
	// Response details
	Message	string	`json:"message"`
}

cacheOptions

cacheOptions exists to transfer options from this middleware down the chain to the cache writer

Field name Field type Comment
key

string

No comment on field.
cacheOnlyResponseCodes

[]int

No comment on field.
timeout

int64

No comment on field.
type cacheOptions struct {
	key			string
	cacheOnlyResponseCodes	[]int
	timeout			int64
}

customResponseWriter

customResponseWriter is a wrapper around standard http.ResponseWriter plus it tracks if response was sent and what status code was sent

Field name Field type Comment

http.ResponseWriter

No comment on field.
responseSent

bool

No comment on field.
statusCodeSent

int

No comment on field.
copyData

bool

No comment on field.
data

[]byte

No comment on field.
dataLength

int64

No comment on field.
type customResponseWriter struct {
	http.ResponseWriter
	responseSent	bool
	statusCodeSent	int
	copyData	bool
	data		[]byte
	dataLength	int64
}

dashboardConfigPayload

This type doesn't have documentation.

Field name Field type Comment
DashboardConfig

struct { Hostname string Port int UseTLS bool }

No comment on field.
TimeStamp

int64

No comment on field.
type dashboardConfigPayload struct {
	DashboardConfig	struct {
		Hostname	string
		Port		int
		UseTLS		bool
	}
	TimeStamp	int64
}

dialFn

This type doesn't have documentation.

Field name Field type Comment
type

func(network string, address string) (net.Conn, error)

No comment on field.
type dialFn func(network string, address string) (net.Conn, error)

dummyStreamingMiddleware

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type dummyStreamingMiddleware struct {
	*BaseMiddleware
}

eventKey

This type doesn't have documentation.

Field name Field type Comment
job

string

No comment on field.
event

string

No comment on field.
suffix

string

No comment on field.
type eventKey struct {
	job	string
	event	string
	suffix	string
}

explicitRouteHandler

This type doesn't have documentation.

Field name Field type Comment
prefix

string

No comment on field.
handler

http.Handler

No comment on field.
type explicitRouteHandler struct {
	prefix	string
	handler	http.Handler
}

generalStores

This type doesn't have documentation.

Field name Field type Comment
redisStore

storage.Handler

No comment on field.
type generalStores struct {
	redisStore, redisOrgStore, healthStore, rpcAuthStore, rpcOrgStore storage.Handler
}

h2cWrapper

h2cWrapper tracks handleWrapper for swapping w.router on reloads.

Field name Field type Comment
w

*handleWrapper

No comment on field.
h

http.Handler

No comment on field.
type h2cWrapper struct {
	w	*handleWrapper
	h	http.Handler
}

handleWrapper

handleWrapper's only purpose is to allow router to be dynamically replaced

Field name Field type Comment
router

http.Handler

No comment on field.
maxContentLength

int64

No comment on field.
maxRequestBodySize

int64

No comment on field.
type handleWrapper struct {
	router	http.Handler	// *mux.Router

	maxContentLength	int64
	maxRequestBodySize	int64
}

httpProxyHandler

Taken from https://medium.com/@mlowicki/http-s-proxy-in-golang-in-less-than-100-lines-of-code-6a51c2f2c38c

Field name Field type Comment
proto

string

No comment on field.
URL

string

No comment on field.
server

*http.Server

No comment on field.
listener

net.Listener

No comment on field.
type httpProxyHandler struct {
	proto		string
	URL		string
	server		*http.Server
	listener	net.Listener
}

introspectionCache

This type doesn't have documentation.

Field name Field type Comment

*storage.RedisCluster

No comment on field.
type introspectionCache struct {
	*storage.RedisCluster
}

maxLatencyWriter

This type doesn't have documentation.

Field name Field type Comment
dst

writeFlusher

No comment on field.
latency

time.Duration

No comment on field.
mu

sync.Mutex

No comment on field.
t

*time.Timer

No comment on field.
flushPending

bool

No comment on field.
type maxLatencyWriter struct {
	dst	writeFlusher
	latency	time.Duration	// non-zero; negative means to flush immediately

	mu		sync.Mutex	// protects t, flushPending, and dst.Flush
	t		*time.Timer
	flushPending	bool
}

memConnProvider

This type doesn't have documentation.

Field name Field type Comment
listener

net.Listener

No comment on field.
provider

*memconn.Provider

No comment on field.
expireAt

time.Time

No comment on field.
type memConnProvider struct {
	listener	net.Listener
	provider	*memconn.Provider
	expireAt	time.Time
}

noopUpstreamBasicAuth

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type noopUpstreamBasicAuth struct {
	*BaseMiddleware
}

noopUpstreamOAuth

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
type noopUpstreamOAuth struct {
	*BaseMiddleware
}

nopCloser

nopCloser is just like ioutil's, but here to let us re-read the same buffer inside by moving position to the start every time we done with reading

Field name Field type Comment

io.ReadSeeker

No comment on field.
type nopCloser struct {
	io.ReadSeeker
}

nopCloserBuffer

nopCloserBuffer is like nopCloser above but uses pointer receiver for seeking within an internal bytes.Buffer reference.

Field name Field type Comment
reader

io.ReadCloser

No comment on field.
once

sync.Once

No comment on field.
buf

bytes.Buffer

No comment on field.
position

int64

No comment on field.
type nopCloserBuffer struct {
	reader		io.ReadCloser
	once		sync.Once
	buf		bytes.Buffer
	position	int64
}

orgChanMapMu

This type doesn't have documentation.

Field name Field type Comment

sync.Mutex

No comment on field.
channels

map[string](chan bool)

No comment on field.
type orgChanMapMu struct {
	sync.Mutex
	channels	map[string](chan bool)
}

paginatedOAuthClientTokens

This type doesn't have documentation.

Field name Field type Comment
Pagination

paginationStatus

No comment on field.
Tokens

[]OAuthClientToken

No comment on field.
type paginatedOAuthClientTokens struct {
	Pagination	paginationStatus
	Tokens		[]OAuthClientToken
}

paginationStatus

paginationStatus provides more information about a paginated data set

Field name Field type Comment
PageNum

int

No comment on field.
PageTotal

int

No comment on field.
PageSize

int

No comment on field.
type paginationStatus struct {
	PageNum		int	`json:"page_num"`
	PageTotal	int	`json:"page_total"`
	PageSize	int	`json:"page_size"`
}

postReceiveHttpHook

This type doesn't have documentation.

Field name Field type Comment
m

*GraphQLMiddleware

No comment on field.
type postReceiveHttpHook struct {
	m *GraphQLMiddleware
}

preSendHttpHook

This type doesn't have documentation.

Field name Field type Comment
m

*GraphQLMiddleware

No comment on field.
type preSendHttpHook struct {
	m *GraphQLMiddleware
}

prefixBuffer

This type doesn't have documentation.

Field name Field type Comment

*bytes.Buffer

No comment on field.
prefixLen

int

No comment on field.
type prefixBuffer struct {
	*bytes.Buffer
	prefixLen	int
}

proxy

This type doesn't have documentation.

Field name Field type Comment
listener

net.Listener

No comment on field.
port

int

No comment on field.
protocol

string

No comment on field.
useProxyProtocol

bool

No comment on field.
router

*mux.Router

No comment on field.
httpServer

*http.Server

No comment on field.
tcpProxy

*tcp.Proxy

No comment on field.
started

bool

No comment on field.
type proxy struct {
	listener		net.Listener
	port			int
	protocol		string
	useProxyProtocol	bool
	router			*mux.Router
	httpServer		*http.Server
	tcpProxy		*tcp.Proxy
	started			bool
}

proxyMux

This type doesn't have documentation.

Field name Field type Comment

sync.RWMutex

No comment on field.
proxies

[]*proxy

No comment on field.
again

again.Again

No comment on field.
track404Logs

bool

No comment on field.
type proxyMux struct {
	sync.RWMutex
	proxies		[]*proxy
	again		again.Again
	track404Logs	bool
}

redisChannelHook

This type doesn't have documentation.

Field name Field type Comment
notifier

RedisNotifier

No comment on field.
formatter

logrus.Formatter

No comment on field.
type redisChannelHook struct {
	notifier	RedisNotifier
	formatter	logrus.Formatter
}

sessionFailReason

This type doesn't have documentation.

Field name Field type Comment
type

uint

No comment on field.
type sessionFailReason uint

statsdCmdKind

This type doesn't have documentation.

Field name Field type Comment
type

int

No comment on field.
type statsdCmdKind int

statsdEmitCmd

This type doesn't have documentation.

Field name Field type Comment
Kind

statsdCmdKind

No comment on field.
Job

string

No comment on field.
Event

string

No comment on field.
Nanos

int64

No comment on field.
Value

float64

No comment on field.
Status

health.CompletionStatus

No comment on field.
type statsdEmitCmd struct {
	Kind	statsdCmdKind
	Job	string
	Event	string
	Nanos	int64
	Value	float64
	Status	health.CompletionStatus
}

swaggerParameterBodies

parameterBodies swagger:response parameterBodies

Field name Field type Comment
APIStatusMessage

apiStatusMessage

in: body

APIModifyKeySuccess

apiModifyKeySuccess

in: body

NewClientRequest

NewClientRequest

in: body

APIDefinition

apidef.APIDefinition

in: body

SessionState

user.SessionState

in: body

APIAllKeys

apiAllKeys

in:body

OAuthClientToken

OAuthClientToken

in: body

type swaggerParameterBodies struct {
	// in: body
	APIStatusMessage	apiStatusMessage
	// in: body
	APIModifyKeySuccess	apiModifyKeySuccess
	// in: body
	NewClientRequest	NewClientRequest
	// in: body
	APIDefinition	apidef.APIDefinition
	// in: body
	SessionState	user.SessionState
	// in:body
	APIAllKeys	apiAllKeys
	// in: body
	OAuthClientToken	OAuthClientToken
}

switchProtocolCopier

switchProtocolCopier exists so goroutines proxying data back and forth have nice names in stacks.

Field name Field type Comment
user

io.ReadWriter

No comment on field.
type switchProtocolCopier struct {
	user, backend io.ReadWriter
}

testMessageAdapter

This type doesn't have documentation.

Field name Field type Comment
Msg

string

No comment on field.
type testMessageAdapter struct {
	Msg string
}

traceHttpRequest

This type doesn't have documentation.

Field name Field type Comment
Method

string

No comment on field.
Path

string

No comment on field.
Body

string

No comment on field.
Headers

http.Header

No comment on field.
type traceHttpRequest struct {
	Method	string		`json:"method"`
	Path	string		`json:"path"`
	Body	string		`json:"body"`
	Headers	http.Header	`json:"headers"`
}

traceRequest

TraceRequest is for tracing an HTTP request swagger:model TraceRequest

Field name Field type Comment
Request

*traceHttpRequest

No comment on field.
Spec

*apidef.APIDefinition

No comment on field.
OAS

*oas.OAS

No comment on field.
type traceRequest struct {
	Request	*traceHttpRequest	`json:"request"`
	Spec	*apidef.APIDefinition	`json:"spec"`
	OAS	*oas.OAS		`json:"oas"`
}

traceResponse

TraceResponse is for tracing an HTTP response swagger:model TraceResponse

Field name Field type Comment
Message

string

No comment on field.
Response

string

No comment on field.
Logs

string

No comment on field.
type traceResponse struct {
	Message		string	`json:"message"`
	Response	string	`json:"response"`
	Logs		string	`json:"logs"`
}

variableReplaceRoundTripper

This type doesn't have documentation.

Field name Field type Comment
next

http.RoundTripper

No comment on field.
outReq

*http.Request

No comment on field.
gw

*Gateway

No comment on field.
type variableReplaceRoundTripper struct {
	next	http.RoundTripper
	outReq	*http.Request
	gw	*Gateway
}

wrapMiddleware

This type doesn't have documentation.

Field name Field type Comment

*BaseMiddleware

No comment on field.
mw

model.Middleware

No comment on field.
type wrapMiddleware struct {
	*BaseMiddleware
	mw	model.Middleware
}

writeFlusher

This type doesn't have documentation.

Field name Field type Comment
type

any

No comment on field.
type writeFlusher interface {
	io.Writer
	http.Flusher
}

Functions

func APILoopingName

func APILoopingName(name string) string {
	return replaceNonAlphaNumeric(trimCategories(name))
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func AuthFailed

TODO: move this method to base middleware?

func AuthFailed(m TykMiddleware, r *http.Request, token string) {
	m.Base().FireEvent(EventAuthFailure, EventKeyFailureMeta{
		EventMetaDefault:	EventMetaDefault{Message: "Auth Failure", OriginatingRequest: EncodeRequestToEvent(r)},
		Path:			r.URL.Path,
		Origin:			request.RealIP(r),
		Key:			token,
	})
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: request.RealIP.

func BuildAPI

func BuildAPI(apiGens ...func(spec *APISpec)) (specs []*APISpec) {
	if len(apiGens) == 0 {
		apiGens = append(apiGens, func(spec *APISpec) {})
	}

	for idx, gen := range apiGens {
		spec := &APISpec{APIDefinition: &apidef.APIDefinition{}}
		if err := json.Unmarshal([]byte(sampleAPI), spec.APIDefinition); err != nil {
			panic(err)
		}
		if idx > 0 {
			spec.APIID = randStringBytes(8)
		}
		gen(spec)
		specs = append(specs, spec)
	}

	return specs
}

Cognitive complexity: 12, Cyclomatic complexity: 5

Uses: apidef.APIDefinition, json.Unmarshal.

func BuildOASAPI

func BuildOASAPI(oasGens ...func(oasDef *oas.OAS)) (specs []*APISpec) {
	for _, gen := range oasGens {
		oasAPI := getSampleOASAPI()
		gen(&oasAPI)

		var nativeAPIDefinition apidef.APIDefinition
		oasAPI.ExtractTo(&nativeAPIDefinition)
		nativeAPIDefinition.IsOAS = true
		spec := &APISpec{APIDefinition: &nativeAPIDefinition, OAS: oasAPI}
		specs = append(specs, spec)
	}

	return specs
}

Cognitive complexity: 4, Cyclomatic complexity: 2

Uses: apidef.APIDefinition.

func CheckPortWhiteList

func CheckPortWhiteList(w map[string]config.PortWhiteList, listenPort int, protocol string) error {

	if w != nil {
		if ls, ok := w[protocol]; ok {
			if ls.Match(listenPort) {
				return nil
			}
		}
	}

	return fmt.Errorf("%s:%d trying to open disabled port", protocol, listenPort)
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: fmt.Errorf.

func CloneAPI

func CloneAPI(a *APISpec) *APISpec {
	new := &APISpec{}
	new.APIDefinition = &apidef.APIDefinition{}
	*new.APIDefinition = *a.APIDefinition

	return new
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: apidef.APIDefinition.

func CoProcessLog

CoProcessLog is a bridge for using Tyk log from CP.

func CoProcessLog(CMessage, CLogLevel * /*line :88:40*/ _Ctype_char /*line :88:46*/) {
	message := ( /*line :89:13*/ _Cfunc_GoString /*line :89:22*/)(CMessage)
	logLevel := ( /*line :90:14*/ _Cfunc_GoString /*line :90:23*/)(CLogLevel)
	switch logLevel {
	case "debug":
		log.WithFields(logrus.Fields{
			"prefix": "python",
		}).Debug(message)
	case "error":
		log.WithFields(logrus.Fields{
			"prefix": "python",
		}).Error(message)
	case "warning":
		log.WithFields(logrus.Fields{
			"prefix": "python",
		}).Warning(message)
	default:
		log.WithFields(logrus.Fields{
			"prefix": "python",
		}).Info(message)
	}
}

Cognitive complexity: 9, Cyclomatic complexity: 5

Uses: logrus.Fields.

func CreateCoProcessMiddleware

CreateCoProcessMiddleware initializes a new CP middleware, takes hook type (pre, post, etc.), hook name ("my_hook") and driver ("python").

func CreateCoProcessMiddleware(hookName string, hookType coprocess.HookType, mwDriver apidef.MiddlewareDriver, baseMid *BaseMiddleware) func(http.Handler) http.Handler {
	dMiddleware := &CoProcessMiddleware{
		BaseMiddleware:		baseMid,
		HookType:		hookType,
		HookName:		hookName,
		MiddlewareDriver:	mwDriver,
		successHandler:		&SuccessHandler{baseMid.Copy()},
	}

	return baseMid.Gw.createMiddleware(dMiddleware)
}

Cognitive complexity: 2, Cyclomatic complexity: 1

func CreateJWKToken

func CreateJWKToken(jGen ...func(*jwt.Token)) string {
	// Create the token
	token := jwt.New(jwt.GetSigningMethod("RS512"))
	// Set the token ID

	if len(jGen) > 0 {
		jGen[0](token)
	}

	// Sign and get the complete encoded token as a string
	signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(jwtRSAPrivKey))
	if err != nil {
		panic("Couldn't extract private key: " + err.Error())
	}
	tokenString, err := token.SignedString(signKey)
	if err != nil {
		panic("Couldn't create JWT token: " + err.Error())
	}

	return tokenString
}

Cognitive complexity: 6, Cyclomatic complexity: 4

func CreateJWKTokenECDSA

func CreateJWKTokenECDSA(jGen ...func(*jwt.Token)) string {
	// Create the token
	token := jwt.New(jwt.GetSigningMethod("ES256"))
	// Set the token ID

	if len(jGen) > 0 {
		jGen[0](token)
	}

	// Sign and get the complete encoded token as a string
	signKey, err := jwt.ParseECPrivateKeyFromPEM([]byte(jwtECDSAPrivateKey))
	if err != nil {
		panic("Couldn't extract private key: " + err.Error())
	}
	tokenString, err := token.SignedString(signKey)
	if err != nil {
		panic("Couldn't create JWT token: " + err.Error())
	}

	return tokenString
}

Cognitive complexity: 6, Cyclomatic complexity: 4

func CreateSession

Deprecated: Use Test.CreateSession instead.

func CreateSession(gw *Gateway, sGen ...func(s *user.SessionState)) string {
	key := gw.generateToken("default", "")
	session := CreateStandardSession()
	if len(sGen) > 0 {
		sGen[0](session)
	}

	if session.Certificate != "" {
		key = gw.generateToken("default", session.Certificate)
	}

	hashKeys := gw.GetConfig().HashKeys
	hashedKey := storage.HashKey(key, hashKeys)
	err := gw.GlobalSessionManager.UpdateSession(hashedKey, session, 60, hashKeys)
	if err != nil {
		log.WithError(err).Error("updating session.")
	}
	return key
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: storage.HashKey.

func CreateStandardPolicy

func CreateStandardPolicy() *user.Policy {
	return &user.Policy{
		OrgID:			"default",
		Rate:			1000.0,
		Per:			1.0,
		QuotaMax:		-1,
		QuotaRenewalRate:	-1,
		AccessRights:		map[string]user.AccessDefinition{},
		Active:			true,
		KeyExpiresIn:		60,
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: user.AccessDefinition, user.Policy.

func CreateStandardSession

func CreateStandardSession() *user.SessionState {
	session := user.NewSessionState()
	session.Rate = 10000
	session.Allowance = session.Rate
	session.LastCheck = time.Now().Unix()
	session.Per = 60
	session.Expires = -1
	session.QuotaRenewalRate = 300	// 5 minutes
	session.QuotaRenews = time.Now().Unix() + 20
	session.QuotaRemaining = 10
	session.QuotaMax = -1
	session.Tags = []string{}
	session.MetaData = make(map[string]interface{})
	session.OrgID = "default"
	return session
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: time.Now, user.NewSessionState.

func DoCoprocessReload

func DoCoprocessReload() {
	log.WithFields(logrus.Fields{
		"prefix": "coprocess",
	}).Info("Reloading middlewares")
	if dispatcher := loadedDrivers[apidef.PythonDriver]; dispatcher != nil {
		dispatcher.Reload()
	}
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: apidef.PythonDriver, logrus.Fields.

func DurationToMillisecond

func DurationToMillisecond(d time.Duration) float64 {
	return float64(d) / 1e6
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func EnsureTransport

EnsureTransport sanitizes host/protocol pairs and returns a valid URL.

func EnsureTransport(host, protocol string) string {
	host = strings.TrimSpace(host)
	protocol = strings.TrimSpace(protocol)

	// sanitize protocol
	if protocol == "" {
		protocol = "http"
	}

	// if host has no protocol, amend it
	if !strings.Contains(host, "://") {
		host = protocol + "://" + host
	}

	host = strings.Replace(host, "h2c://", "http://", 1)

	u, err := url.Parse(host)
	if err != nil {
		return host
	}
	return u.String()
}

Cognitive complexity: 5, Cyclomatic complexity: 4

Uses: strings.Contains, strings.Replace, strings.TrimSpace, url.Parse.

func GenerateTestBinaryData

func GenerateTestBinaryData() (buf *bytes.Buffer) {
	buf = new(bytes.Buffer)
	type testData struct {
		a	float32
		b	float64
		c	uint32
	}
	for i := 0; i < 10; i++ {
		s := &testData{mathrand.Float32(), mathrand.Float64(), mathrand.Uint32()}
		binary.Write(buf, binary.BigEndian, s)
	}
	return buf
}

Cognitive complexity: 4, Cyclomatic complexity: 2

Uses: binary.BigEndian, binary.Write, bytes.Buffer, mathrand.Float32, mathrand.Float64, mathrand.Uint32.

func GetAccessDefinitionByAPIIDOrSession

func GetAccessDefinitionByAPIIDOrSession(session *user.SessionState, api *APISpec) (accessDef *user.AccessDefinition, allowanceScope string, err error) {
	accessDef = &user.AccessDefinition{}
	if len(session.AccessRights) > 0 {
		if rights, ok := session.AccessRights[api.APIID]; !ok {
			return nil, "", errors.New("unexpected apiID")
		} else {
			accessDef.Limit = rights.Limit
			accessDef.FieldAccessRights = rights.FieldAccessRights
			accessDef.RestrictedTypes = rights.RestrictedTypes
			accessDef.AllowedTypes = rights.AllowedTypes
			accessDef.DisableIntrospection = rights.DisableIntrospection
			accessDef.Endpoints = rights.Endpoints
			allowanceScope = rights.AllowanceScope
		}
	}
	if accessDef.Limit.IsEmpty() {
		accessDef.Limit = session.APILimit()
	}

	return accessDef, allowanceScope, nil
}

Cognitive complexity: 9, Cyclomatic complexity: 4

Uses: errors.New, user.AccessDefinition.

func GetCoProcessGrpcServerTargetUrlAsString

func GetCoProcessGrpcServerTargetUrlAsString(targetUrl *url.URL) string {
	return strings.TrimPrefix(targetUrl.String(), "tcp://")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: strings.TrimPrefix.

func GetTLSClient

func GetTLSClient(cert *tls.Certificate, caCert []byte) *http.Client {
	// Setup HTTPS client
	tlsConfig := GetTLSConfig(cert, caCert)

	transport := &http.Transport{TLSClientConfig: tlsConfig}

	return &http.Client{Transport: transport}
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: http.Client, http.Transport.

func GetTLSConfig

func GetTLSConfig(cert *tls.Certificate, caCert []byte) *tls.Config {
	tlsConfig := &tls.Config{}

	if cert != nil {
		tlsConfig.Certificates = []tls.Certificate{*cert}
	}

	if len(caCert) > 0 {
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)
		tlsConfig.RootCAs = caCertPool
		tlsConfig.BuildNameToCertificate()
	} else {
		tlsConfig.InsecureSkipVerify = true
	}

	return tlsConfig
}

Cognitive complexity: 8, Cyclomatic complexity: 3

Uses: tls.Certificate, tls.Config, x509.NewCertPool.

func InitTestMain

func InitTestMain(ctx context.Context, m *testing.M) int {
	test.InitTestMain(ctx, m)

	bundleBackoffMultiplier = 0
	bundleMaxBackoffRetries = 0

	if EnableTestDNSMock {
		var errMock error
		MockHandle, errMock = test.InitDNSMock(test.DomainsToAddresses, nil)
		if errMock != nil {
			panic(errMock)
		}

		defer MockHandle.ShutdownDnsMock()
	}

	exitCode := m.Run()

	return exitCode
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: test.DomainsToAddresses, test.InitDNSMock, test.InitTestMain.

func InstrumentationMW

InstrumentationMW will set basic instrumentation events, variables and timers on API jobs

func InstrumentationMW(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		job := instrument.NewJob("SystemAPICall")

		next.ServeHTTP(w, r)
		job.EventKv("called", health.Kvs{
			"from_ip":	request.RealIP(r),
			"method":	r.Method,
			"endpoint":	r.URL.Path,
			"raw_url":	r.URL.String(),
			"size":		strconv.Itoa(int(r.ContentLength)),
		})
		job.Complete(health.Success)
	})
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: health.Kvs, health.Success, http.HandlerFunc, http.Request, http.ResponseWriter, request.RealIP, strconv.Itoa.

func JSONToFormValues

JSONToFormValues if r has header Content-Type set to application/json this will decode request body as json to map[string]string and adds the key/value pairs in r.Form.

func JSONToFormValues(r *http.Request) error {
	if r.Header.Get("Content-Type") == "application/json" {
		var o map[string]string
		err := json.NewDecoder(r.Body).Decode(&o)
		if err != nil {
			return err
		}
		if len(o) > 0 {
			if r.Form == nil {
				r.Form = make(url.Values)
			}
			for k, v := range o {
				r.Form.Set(k, v)
			}
		}

	}
	return nil
}

Cognitive complexity: 11, Cyclomatic complexity: 6

Uses: json.NewDecoder, url.Values.

func LoadPoliciesFromDir

func LoadPoliciesFromDir(dir string) (map[string]user.Policy, error) {
	policies := make(map[string]user.Policy)
	// Grab json files from directory
	paths, err := filepath.Glob(filepath.Join(dir, "*.json"))
	if err != nil {
		log.Error("error fetch policies path from policies path: ", err)
		return nil, err
	}

	for _, path := range paths {
		log.Info("Loading policy from dir ", path)
		f, err := os.Open(path)
		if err != nil {
			log.Error("Couldn't open policy file from dir: ", err)
			continue
		}
		pol := &user.Policy{}
		if err := json.NewDecoder(f).Decode(pol); err != nil {
			log.Errorf("Couldn't unmarshal policy configuration from dir: %v : %v", path, err)
		}
		f.Close()
		policies[pol.ID] = *pol
	}
	return policies, nil
}

Cognitive complexity: 10, Cyclomatic complexity: 5

Uses: filepath.Glob, filepath.Join, json.NewDecoder, os.Open, user.Policy.

func LoadPoliciesFromFile

func LoadPoliciesFromFile(filePath string) (map[string]user.Policy, error) {
	f, err := os.Open(filePath)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "policy",
		}).Error("Couldn't open policy file: ", err)
		return nil, err
	}
	defer f.Close()

	var policies map[string]user.Policy
	if err := json.NewDecoder(f).Decode(&policies); err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "policy",
		}).Error("Couldn't unmarshal policies: ", err)
		return nil, err
	}
	return policies, nil
}

Cognitive complexity: 6, Cyclomatic complexity: 3

Uses: json.NewDecoder, logrus.Fields, os.Open, user.Policy.

func LoopingUrl

func LoopingUrl(host string) string {
	return LoopScheme + "://" + replaceNonAlphaNumeric(host)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func NewBaseMiddleware

NewBaseMiddleware creates a new *BaseMiddleware. The passed logrus.Entry is duplicated. BaseMiddleware keeps the pointer to *Gateway and *APISpec, as well as Proxy. The logger duplication is used so that basemiddleware copies can be created for different middleware.

func NewBaseMiddleware(gw *Gateway, spec *APISpec, proxy ReturningHttpHandler, logger *logrus.Entry) *BaseMiddleware {
	if logger == nil {
		logger = logrus.NewEntry(log)
	}
	baseMid := &BaseMiddleware{
		Spec:	spec,
		Proxy:	proxy,
		logger:	logger.Dup(),
		Gw:	gw,
	}

	for _, v := range baseMid.Spec.VersionData.Versions {
		if len(v.ExtendedPaths.CircuitBreaker) > 0 {
			baseMid.Spec.CircuitBreakerEnabled = true
		}
		if len(v.ExtendedPaths.HardTimeouts) > 0 {
			baseMid.Spec.EnforcedTimeoutEnabled = true
		}
	}

	return baseMid
}

Cognitive complexity: 10, Cyclomatic complexity: 5

Uses: logrus.NewEntry.

func NewGateway

func NewGateway(config config.Config, ctx context.Context) *Gateway {
	gw := &Gateway{
		DefaultProxyMux: &proxyMux{
			again: again.New(),
		},
		ctx:	ctx,
	}
	gw.SetConfig(config)

	gw.Analytics = RedisAnalyticsHandler{Gw: gw}
	sessionManager := DefaultSessionManager{Gw: gw}
	gw.GlobalSessionManager = SessionHandler(&sessionManager)
	gw.DefaultOrgStore = DefaultSessionManager{Gw: gw}
	gw.DefaultQuotaStore = DefaultSessionManager{Gw: gw}
	gw.SessionMonitor = Monitor{Gw: gw}
	gw.HostCheckTicker = make(chan struct{})
	gw.HostCheckerClient = &http.Client{
		Timeout: 500 * time.Millisecond,
	}
	gw.ConnectionWatcher = httputil.NewConnectionWatcher()

	gw.cacheCreate()

	gw.apisByID = map[string]*APISpec{}
	gw.apisHandlesByID = new(sync.Map)

	gw.policiesByID = make(map[string]user.Policy)

	// reload
	gw.reloadQueue = make(chan func())
	// only for tests
	gw.ReloadTestCase = NewReloadMachinery()
	gw.TestBundles = map[string]map[string]string{}

	gw.StorageConnectionHandler = storage.NewConnectionHandler(ctx)

	gw.SetNodeID("solo-" + uuid.New())
	gw.SessionID = uuid.New()

	return gw
}

Cognitive complexity: 11, Cyclomatic complexity: 1

Uses: again.New, http.Client, httputil.NewConnectionWatcher, storage.NewConnectionHandler, sync.Map, time.Millisecond, user.Policy, uuid.New.

func NewReloadMachinery

func NewReloadMachinery() *ReloadMachinery {
	return &ReloadMachinery{
		reloadTick: make(chan time.Time),
	}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: time.Time.

func NewSessionLimiter

NewSessionLimiter initializes the session limiter.

The session limiter initializes the storage required for rate limiters. It supports two storage types: redis and local. If redis storage is configured, then redis will be used. If local storage is configured, then in-memory counters will be used. If no storage is configured, it falls back onto the default gateway storage configuration.

func NewSessionLimiter(ctx context.Context, conf *config.Config, drlManager *drl.DRL) SessionLimiter {
	sessionLimiter := SessionLimiter{
		ctx:		ctx,
		drlManager:	drlManager,
		config:		conf,
		bucketStore:	memorycache.New(ctx),
	}

	log.Infof("[RATELIMIT] %s", conf.RateLimit.String())

	storageConf := conf.GetRateLimiterStorage()

	switch storageConf.Type {
	case "redis":
		sessionLimiter.limiterStorage = rate.NewStorage(storageConf)
	}

	sessionLimiter.smoothing = rate.NewSmoothing(sessionLimiter.limiterStorage)

	return sessionLimiter
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: memorycache.New, rate.NewSmoothing, rate.NewStorage.

func NewStatsDSink

func NewStatsDSink(addr string, options *StatsDSinkOptions) (*StatsDSink, error) {
	c, err := net.ListenPacket("udp", ":0")
	if err != nil {
		return nil, err
	}

	ra, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return nil, err
	}

	s := &StatsDSink{
		udpConn:	c.(*net.UDPConn),
		udpAddr:	ra,
		cmdChan:	make(chan statsdEmitCmd, cmdChanBuffSize),
		drainDoneChan:	make(chan struct{}),
		stopDoneChan:	make(chan struct{}),
		flushPeriod:	100 * time.Millisecond,
		prefixBuffers:	map[eventKey]prefixBuffer{},
	}

	if options != nil {
		s.options = *options
		if s.options.SanitizationFunc == nil {
			s.options.SanitizationFunc = sanitizeKey
		}
	} else {
		s.options = defaultStatsDOptions
	}

	go s.loop()

	return s, nil
}

Cognitive complexity: 14, Cyclomatic complexity: 5

Uses: net.ListenPacket, net.ResolveUDPAddr, net.UDPConn, time.Millisecond.

func NewVersionHandler

func NewVersionHandler(getApiDef func(string) (*apidef.APIDefinition, error)) *VersionsHandler {
	return &VersionsHandler{getApiDef: getApiDef}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func NormalisePath

func NormalisePath(a *analytics.AnalyticsRecord, globalConfig *config.Config) {

	if globalConfig.AnalyticsConfig.NormaliseUrls.NormaliseUUIDs {
		a.Path = globalConfig.AnalyticsConfig.NormaliseUrls.CompiledPatternSet.UUIDs.ReplaceAllString(a.Path, "{uuid}")
	}

	if globalConfig.AnalyticsConfig.NormaliseUrls.NormaliseULIDs {
		a.Path = globalConfig.AnalyticsConfig.NormaliseUrls.CompiledPatternSet.ULIDs.ReplaceAllString(a.Path, "{ulid}")
	}

	if globalConfig.AnalyticsConfig.NormaliseUrls.NormaliseNumbers {
		a.Path = globalConfig.AnalyticsConfig.NormaliseUrls.CompiledPatternSet.IDs.ReplaceAllString(a.Path, "/{id}")
	}

	for _, r := range globalConfig.AnalyticsConfig.NormaliseUrls.CompiledPatternSet.Custom {
		a.Path = r.ReplaceAllString(a.Path, "{var}")
	}
}

Cognitive complexity: 9, Cyclomatic complexity: 5

func ParseRSAPublicKey

func ParseRSAPublicKey(data []byte) (interface{}, error) {
	input := data
	block, _ := pem.Decode(data)
	if block != nil {
		input = block.Bytes
	}
	var pub interface{}
	var err error
	pub, err = x509.ParsePKIXPublicKey(input)
	if err != nil {
		cert, err0 := x509.ParseCertificate(input)
		if err0 != nil {
			return nil, err0
		}
		pub = cert.PublicKey
		err = nil
	}
	return pub, err
}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: pem.Decode, x509.ParseCertificate, x509.ParsePKIXPublicKey.

func ProtoMap

ProtoMap is a helper function for maps with string slice values.

func ProtoMap(inputMap map[string][]string) map[string]string {
	newMap := make(map[string]string)

	if inputMap != nil {
		for k, v := range inputMap {
			newMap[k] = v[0]
		}
	}

	return newMap
}

Cognitive complexity: 5, Cyclomatic complexity: 3

func ProtoSessionState

ProtoSessionState takes a standard SessionState and outputs a SessionState object compatible with Protocol Buffers.

func ProtoSessionState(session *user.SessionState) *coprocess.SessionState {

	accessDefinitions := make(map[string]*coprocess.AccessDefinition, len(session.AccessRights))

	for key, accessDefinition := range session.AccessRights {
		var allowedUrls []*coprocess.AccessSpec
		for _, allowedURL := range accessDefinition.AllowedURLs {
			accessSpec := &coprocess.AccessSpec{
				Url:		allowedURL.URL,
				Methods:	allowedURL.Methods,
			}
			allowedUrls = append(allowedUrls, accessSpec)
		}

		accessDefinitions[key] = &coprocess.AccessDefinition{
			ApiName:	accessDefinition.APIName,
			ApiId:		accessDefinition.APIID,
			Versions:	accessDefinition.Versions,
			AllowedUrls:	allowedUrls,
		}
	}

	basicAuthData := &coprocess.BasicAuthData{
		Password:	session.BasicAuthData.Password,
		Hash:		string(session.BasicAuthData.Hash),
	}
	jwtData := &coprocess.JWTData{
		Secret: session.JWTData.Secret,
	}
	monitor := &coprocess.Monitor{
		TriggerLimits: session.Monitor.TriggerLimits,
	}

	metadata := make(map[string]string)
	if len(session.MetaData) > 0 {
		for k, v := range session.MetaData {
			switch v.(type) {
			case string:
				metadata[k] = v.(string)
			default:
				jsonValue, err := json.Marshal(v)
				if err != nil {
					log.WithFields(logrus.Fields{
						"prefix": "coprocess",
					}).WithError(err).Error("Couldn't encode session metadata")
					continue
				}
				metadata[k] = string(jsonValue)
			}
		}
	}

	return &coprocess.SessionState{
		LastCheck:			session.LastCheck,
		Allowance:			session.Allowance,
		Rate:				session.Rate,
		Per:				session.Per,
		Expires:			session.Expires,
		QuotaMax:			session.QuotaMax,
		QuotaRenews:			session.QuotaRenews,
		QuotaRemaining:			session.QuotaRemaining,
		QuotaRenewalRate:		session.QuotaRenewalRate,
		AccessRights:			accessDefinitions,
		OrgId:				session.OrgID,
		OauthClientId:			session.OauthClientID,
		OauthKeys:			session.OauthKeys,
		BasicAuthData:			basicAuthData,
		JwtData:			jwtData,
		HmacEnabled:			session.HMACEnabled,
		HmacSecret:			session.HmacSecret,
		IsInactive:			session.IsInactive,
		ApplyPolicyId:			session.ApplyPolicyID,
		ApplyPolicies:			session.ApplyPolicies,
		DataExpires:			session.DataExpires,
		Monitor:			monitor,
		Metadata:			metadata,
		EnableDetailedRecording:	session.EnableDetailRecording || session.EnableDetailedRecording,
		Tags:				session.Tags,
		Alias:				session.Alias,
		LastUpdated:			session.LastUpdated,
		IdExtractorDeadline:		session.IdExtractorDeadline,
		SessionLifetime:		session.SessionLifetime,
	}
}

Cognitive complexity: 23, Cyclomatic complexity: 9

Uses: coprocess.AccessDefinition, coprocess.AccessSpec, coprocess.BasicAuthData, coprocess.JWTData, coprocess.Monitor, coprocess.SessionState, json.Marshal, logrus.Fields.

func ProxyHandler

ProxyHandler Proxies requests through to their final destination, if they make it through the middleware chain.

func ProxyHandler(p *ReverseProxy, apiSpec *APISpec) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		baseMid := &BaseMiddleware{Spec: apiSpec, Proxy: p, Gw: p.Gw}
		handler := SuccessHandler{baseMid}
		// Skip all other execution
		handler.ServeHTTP(w, r)
	})
}

Cognitive complexity: 3, Cyclomatic complexity: 1

Uses: http.HandlerFunc, http.Request, http.ResponseWriter.

func RevokeAllTokens

func RevokeAllTokens(storage ExtendedOsinStorageInterface, clientId, clientSecret string) (int, []string, error) {
	resp := []string{}
	client, err := storage.GetClient(clientId)
	log.Debug("Revoke all tokens")
	if err != nil {
		return http.StatusNotFound, resp, errors.New("error getting oauth client")
	}

	if client.GetSecret() != clientSecret {
		return http.StatusUnauthorized, resp, errors.New(oauthClientSecretWrong)
	}

	clientTokens, err := storage.GetClientTokens(clientId)
	if err != nil {
		return http.StatusBadRequest, resp, errors.New("cannot retrieve client tokens")
	}

	log.Debug("Tokens found to be revoked:", len(clientTokens))
	for _, token := range clientTokens {
		access, err := storage.LoadAccess(token.Token)
		if err == nil {
			resp = append(resp, access.AccessToken)
			storage.RemoveAccess(access.AccessToken)
			storage.RemoveRefresh(access.RefreshToken)
		} else {
			log.Debug("error loading access:", err.Error())
		}
	}

	return http.StatusOK, resp, nil
}

Cognitive complexity: 14, Cyclomatic complexity: 6

Uses: errors.New, http.StatusBadRequest, http.StatusNotFound, http.StatusOK, http.StatusUnauthorized.

func RevokeToken

func RevokeToken(storage ExtendedOsinStorageInterface, token, tokenTypeHint string) {
	switch tokenTypeHint {
	case accessToken:
		storage.RemoveAccess(token)
	case refreshToken:
		storage.RemoveRefresh(token)
	default:
		storage.RemoveAccess(token)
		storage.RemoveRefresh(token)
	}
}

Cognitive complexity: 4, Cyclomatic complexity: 4

func Start

func Start() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Set up signal handling for graceful shutdown
	sigChan := make(chan os.Signal, 1)
	// Only listen for SIGTERM which is what Kubernetes sends
	signal.Notify(sigChan, syscall.SIGTERM)

	// Initialize everything else as normal
	cli.Init(confPaths)
	cli.Parse()
	// Stop gateway process if not running in "start" mode:
	if !cli.DefaultMode {
		os.Exit(0)
	}

	gwConfig := config.Config{}
	if err := config.Load(confPaths, &gwConfig); err != nil {
		mainLog.Errorf("Error loading config, using defaults: %v", err)

		defaultConfig, err := config.NewDefaultWithEnv()
		if err != nil {
			mainLog.Fatalf("Error falling back to default config with env: %v", err)
		}
		gwConfig = *defaultConfig
	}

	gw := NewGateway(gwConfig, ctx)
	gwConfig = gw.GetConfig()

	go func() {
		sig := <-sigChan
		// This case handles SIGTERM for Kubernetes shutdowns
		mainLog.Infof("SIGTERM received: %v. Initiating graceful shutdown...", sig)
		// Cancel the context to notify all goroutines
		cancel()

		// Perform graceful shutdown
		shutdownCtx, shutdownCancel := context.WithTimeout(
			context.Background(), time.Duration(gwConfig.GracefulShutdownTimeoutDuration)*time.Second)
		defer shutdownCancel()

		if err := gw.gracefulShutdown(shutdownCtx); err != nil {
			mainLog.Errorf("Graceful shutdown error: %v", err)
		}
	}()

	if err := gw.initSystem(); err != nil {
		mainLog.Fatalf("Error initialising system: %v", err)
	}

	if !gw.isRunningTests() && gwConfig.ControlAPIPort == 0 {
		mainLog.Warn("The control_api_port should be changed for production")
	}

	gw.setupPortsWhitelist()
	gw.keyGen = DefaultKeyGenerator{Gw: gw}

	onFork := func() {
		mainLog.Warning("PREPARING TO FORK")

		// if controlListener != nil {
		// 	if err := controlListener.Close(); err != nil {
		// 		mainLog.Error("Control listen handler exit: ", err)
		// 	}
		// 	mainLog.Info("Control listen closed")
		// }

		if gwConfig.UseDBAppConfigs {
			mainLog.Info("Stopping heartbeat")
			gw.DashService.StopBeating()
			mainLog.Info("Waiting to de-register")
			time.Sleep(10 * time.Second)

			os.Setenv("TYK_SERVICE_NONCE", gw.ServiceNonce)
			os.Setenv("TYK_SERVICE_NODEID", gw.GetNodeID())
		}
	}
	err := again.ListenFrom(&gw.DefaultProxyMux.again, onFork)
	if err != nil {
		mainLog.Errorf("Initializing again %s", err)
	}

	if tr := gwConfig.Tracer; tr.Enabled {
		mainLog.Warn("OpenTracing is deprecated, use OpenTelemetry instead.")
		trace.SetupTracing(tr.Name, tr.Options)
		trace.SetLogger(mainLog)
		defer trace.Close()
	}

	gw.TracerProvider = otel.InitOpenTelemetry(gw.ctx, mainLog.Logger, &gwConfig.OpenTelemetry,
		gw.GetNodeID(),
		VERSION,
		gw.GetConfig().SlaveOptions.UseRPC,
		gw.GetConfig().SlaveOptions.GroupID,
		gw.GetConfig().DBAppConfOptions.NodeIsSegmented,
		gw.GetConfig().DBAppConfOptions.Tags)

	gw.start()

	unix := time.Now().Unix()

	var (
		memprofile	= fmt.Sprintf("tyk.%d.mprof", unix)
		cpuprofile	= fmt.Sprintf("tyk.%d.prof", unix)
	)

	if *cli.MemProfile {
		mainLog.Debug("Memory profiling active")
		var err error
		if memProfFile, err = os.Create(memprofile); err != nil {
			panic(err)
		}
		defer func() {
			pprof.WriteHeapProfile(memProfFile)
			memProfFile.Close()
		}()
	}
	if *cli.CPUProfile {
		mainLog.Info("Cpu profiling active")
		cpuProfFile, err := os.Create(cpuprofile)
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(cpuProfFile)
		defer pprof.StopCPUProfile()
	}
	if *cli.BlockProfile {
		mainLog.Info("Block profiling active")
		runtime.SetBlockProfileRate(1)
	}
	if *cli.MutexProfile {
		mainLog.Info("Mutex profiling active")
		runtime.SetMutexProfileFraction(1)
	}

	// set var as global so we can export TykTriggerEvent(CEventName, CPayload *C.char)
	GatewayFireSystemEvent = gw.FireSystemEvent
	// TODO: replace goagain with something that support multiple listeners
	// Example: https://gravitational.com/blog/golang-ssh-bastion-graceful-restarts/
	gw.startServer()

	if again.Child() {
		// This is a child process, we need to murder the parent now
		if err := again.Kill(); err != nil {
			mainLog.Fatal(err)
		}
	}
	_, err = again.Wait(&gw.DefaultProxyMux.again)
	if err != nil {
		mainLog.WithError(err).Error("waiting")
	}
	mainLog.Info("Stop signal received.")
	if err = gw.DefaultProxyMux.again.Close(); err != nil {
		mainLog.Error("Closing listeners: ", err)
	}
	// stop analytics workers
	if gwConfig.EnableAnalytics && gw.Analytics.Store == nil {
		gw.Analytics.Stop()
	}

	// write pprof profiles
	writeProfiles()

	if gwConfig.UseDBAppConfigs {
		mainLog.Info("Stopping heartbeat...")
		gw.DashService.StopBeating()
		time.Sleep(2 * time.Second)
		err := gw.DashService.DeRegister()
		if err != nil {
			mainLog.WithError(err).Error("deregistering in dashboard")
		}
	}
	if gwConfig.SlaveOptions.UseRPC {
		store := RPCStorageHandler{
			DoReload:	gw.DoReload,
			Gw:		gw,
		}

		err := store.Disconnect()
		if err != nil {
			mainLog.WithError(err).Error("deregistering in MDCB")
		}
	}

	mainLog.Info("Terminating.")

	time.Sleep(time.Second)
}

Cognitive complexity: 54, Cyclomatic complexity: 27

Uses: again.Child, again.Kill, again.ListenFrom, again.Wait, cli.BlockProfile, cli.CPUProfile, cli.DefaultMode, cli.Init, cli.MemProfile, cli.MutexProfile, cli.Parse, config.Config, config.Load, config.NewDefaultWithEnv, context.Background, context.WithCancel, context.WithTimeout, fmt.Sprintf, os.Create, os.Exit, os.Setenv, os.Signal, otel.InitOpenTelemetry, pprof.StartCPUProfile, pprof.StopCPUProfile, pprof.WriteHeapProfile, runtime.SetBlockProfileRate, runtime.SetMutexProfileFraction, signal.Notify, syscall.SIGTERM, time.Duration, time.Now, time.Second, time.Sleep, trace.Close, trace.SetLogger, trace.SetupTracing.

func StartTest

func StartTest(genConf func(globalConf *config.Config), testConfig ...TestConfig) *Test {
	t := &Test{
		dynamicHandlers: make(map[string]http.HandlerFunc),
	}

	// DNS mock enabled by default
	t.config.EnableTestDNSMock = false
	if len(testConfig) > 0 {
		t.config = testConfig[0]
	}

	t.Gw = t.start(genConf)

	return t
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: http.HandlerFunc.

func TestHelperSSEServer

func TestHelperSSEServer(tb testing.TB) *httptest.Server {
	tb.Helper()
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "text/event-stream")
		w.Header().Set("Connection", "keep-alive")

		flusher, ok := w.(http.Flusher)
		assert.True(tb, ok)
		for i := 0; i < 5; i++ {
			fmt.Fprintf(w, "data: %d\n", i)
			flusher.Flush()
			time.Sleep(50 * time.Millisecond)
		}
	}))
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: assert.True, fmt.Fprintf, http.Flusher, http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer, time.Millisecond, time.Sleep.

func TestHelperSSEStreamClient

func TestHelperSSEStreamClient(tb testing.TB, ts *Test, enableWebSockets bool) error {
	tb.Helper()

	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, ts.URL, nil)
	assert.NoError(tb, err)
	req.Header.Set("Accept", "text/event-stream")
	client := http.Client{}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	globalConf := ts.Gw.GetConfig()
	globalConf.HttpServerOptions.EnableWebSockets = enableWebSockets
	ts.Gw.SetConfig(globalConf)

	res, err := client.Do(req)
	assert.NoError(tb, err)

	reader := bufio.NewReader(res.Body)
	defer res.Body.Close()

	i := 0
	okChan := make(chan error)

	go func() {
		for {
			line, err := reader.ReadBytes('\n')
			if err != nil && assert.ErrorContains(tb, err, io.EOF.Error()) {
				err = nil
			}

			assert.NoError(tb, err)

			if len(line) == 0 {
				break
			}

			assert.Equal(tb, fmt.Sprintf("data: %v\n", i), string(line))
			i++
		}
		close(okChan)
	}()

	select {
	case <-ctx.Done():
		return ctx.Err()
	case <-okChan:
	}
	assert.Equal(tb, i, 5)
	return nil
}

Cognitive complexity: 11, Cyclomatic complexity: 7

Uses: assert.Equal, assert.ErrorContains, assert.NoError, bufio.NewReader, context.Background, context.WithTimeout, fmt.Sprintf, http.Client, http.MethodGet, http.NewRequestWithContext, io.EOF, time.Second.

func TestReq

func TestReq(t testing.TB, method, urlStr string, body interface{}) *http.Request {
	return httptest.NewRequest(method, urlStr, TestReqBody(t, body))
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: httptest.NewRequest.

func TestReqBody

func TestReqBody(t testing.TB, body interface{}) io.Reader {
	switch x := body.(type) {
	case []byte:
		return bytes.NewReader(x)
	case string:
		return strings.NewReader(x)
	case io.Reader:
		return x
	case nil:
		return nil
	default:	// JSON objects (structs)
		bs := test.MarshalJSON(t)(x)
		return bytes.NewReader(bs)
	}
}

Cognitive complexity: 7, Cyclomatic complexity: 6

Uses: bytes.NewReader, io.Reader, strings.NewReader, test.MarshalJSON.

func TykGetData

TykGetData is a CoProcess API function for fetching data.

func TykGetData(CKey * /*line :53:23*/ _Ctype_char /*line :53:29*/) * /*line :53:32*/ _Ctype_char /*line :53:38*/ {
	key := ( /*line :54:9*/ _Cfunc_GoString /*line :54:18*/)(CKey)

	// Timeout storing data after 1 second
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	store := getStorageForPython(ctx)

	val, err := store.GetKey(key)
	if err != nil {
		log.WithError(err).Error("could not get key")
	}

	return ( /*line :67:9*/ _Cfunc_CString /*line :67:17*/)(val)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: context.Background, context.WithTimeout, time.Second.

func TykSessionState

TykSessionState takes a coprocess.SessionState (as returned by the Protocol Buffer binding), and outputs a standard Tyk SessionState.

func TykSessionState(session *coprocess.SessionState) *user.SessionState {
	accessDefinitions := make(map[string]user.AccessDefinition, len(session.AccessRights))

	for key, protoAccDef := range session.AccessRights {
		allowedUrls := make([]user.AccessSpec, len(protoAccDef.AllowedUrls))
		for _, protoAllowedURL := range protoAccDef.AllowedUrls {
			allowedUrls = append(allowedUrls, user.AccessSpec{
				URL:		protoAllowedURL.Url,
				Methods:	protoAllowedURL.Methods,
			})
		}
		accessDefinitions[key] = user.AccessDefinition{
			APIName:	protoAccDef.ApiName,
			APIID:		protoAccDef.ApiId,
			Versions:	protoAccDef.Versions,
			AllowedURLs:	allowedUrls,
		}
	}

	var basicAuthData struct {
		Password	string		`json:"password" msg:"password"`
		Hash		user.HashType	`json:"hash_type" msg:"hash_type"`
	}
	if session.BasicAuthData != nil {
		basicAuthData.Password = session.BasicAuthData.Password
		basicAuthData.Hash = user.HashType(session.BasicAuthData.Hash)
	}

	var jwtData struct {
		Secret string `json:"secret" msg:"secret"`
	}
	if session.JwtData != nil {
		jwtData.Secret = session.JwtData.Secret
	}

	var monitor struct {
		TriggerLimits []float64 `json:"trigger_limits" msg:"trigger_limits"`
	}

	if session.Monitor != nil {
		monitor.TriggerLimits = session.Monitor.TriggerLimits
	}

	metadata := make(map[string]interface{})
	if session.Metadata != nil {
		for k, v := range session.Metadata {
			metadata[k] = v
		}
	}

	return &user.SessionState{
		LastCheck:			session.LastCheck,
		Allowance:			session.Allowance,
		Rate:				session.Rate,
		Per:				session.Per,
		MaxQueryDepth:			int(session.MaxQueryDepth),
		Expires:			session.Expires,
		QuotaMax:			session.QuotaMax,
		QuotaRenews:			session.QuotaRenews,
		QuotaRemaining:			session.QuotaRemaining,
		QuotaRenewalRate:		session.QuotaRenewalRate,
		AccessRights:			accessDefinitions,
		OrgID:				session.OrgId,
		OauthClientID:			session.OauthClientId,
		OauthKeys:			session.OauthKeys,
		Certificate:			session.Certificate,
		BasicAuthData:			basicAuthData,
		JWTData:			jwtData,
		HMACEnabled:			session.HmacEnabled,
		HmacSecret:			session.HmacSecret,
		IsInactive:			session.IsInactive,
		ApplyPolicyID:			session.ApplyPolicyId,
		ApplyPolicies:			session.ApplyPolicies,
		DataExpires:			session.DataExpires,
		MetaData:			metadata,
		Monitor:			monitor,
		EnableDetailedRecording:	session.EnableDetailedRecording,
		Tags:				session.Tags,
		Alias:				session.Alias,
		LastUpdated:			session.LastUpdated,
		IdExtractorDeadline:		session.IdExtractorDeadline,
		SessionLifetime:		session.SessionLifetime,
	}
}

Cognitive complexity: 24, Cyclomatic complexity: 8

Uses: user.AccessDefinition, user.AccessSpec, user.HashType, user.SessionState.

func TykStoreData

TykStoreData is a CoProcess API function for storing data.

func TykStoreData(CKey, CValue * /*line :33:33*/ _Ctype_char /*line :33:39*/, CTTL /*line :33:46*/ _Ctype_int /*line :33:51*/) {
	key := ( /*line :34:9*/ _Cfunc_GoString /*line :34:18*/)(CKey)
	value := ( /*line :35:11*/ _Cfunc_GoString /*line :35:20*/)(CValue)
	ttl := int64(CTTL)

	// Timeout storing data after 1 second
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	store := getStorageForPython(ctx)

	err := store.SetKey(key, value, ttl)
	if err != nil {
		log.WithError(err).Error("could not set key")
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: context.Background, context.WithTimeout, time.Second.

func TykTriggerEvent

TykTriggerEvent is a CoProcess API function for triggering Tyk system events.

func TykTriggerEvent(CEventName, CPayload * /*line :76:44*/ _Ctype_char /*line :76:50*/) {
	eventName := ( /*line :77:15*/ _Cfunc_GoString /*line :77:24*/)(CEventName)
	payload := ( /*line :78:13*/ _Cfunc_GoString /*line :78:22*/)(CPayload)

	GatewayFireSystemEvent(apidef.TykEvent(eventName), EventMetaDefault{
		Message: payload,
	})
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: apidef.TykEvent.

func UpdateAPIVersion

func UpdateAPIVersion(spec *APISpec, name string, verGen func(version *apidef.VersionInfo)) {
	version := spec.VersionData.Versions[name]
	verGen(&version)
	spec.VersionData.Versions[name] = version
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func WrapMiddleware

WrapMiddleware returns a new TykMiddleware with the provided base middleware, and the smaller model.Middleware interface. It allows to implement model.Middleware, and use it as a TykMiddleware.

func WrapMiddleware(base *BaseMiddleware, in model.Middleware) TykMiddleware {
	return &wrapMiddleware{
		BaseMiddleware:	base.Copy(),
		mw:		in,
	}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func WrappedCharsetReader

func WrappedCharsetReader(s string, i io.Reader) (io.Reader, error) {
	return charset.NewReader(i, s)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: charset.NewReader.

func (*APISpec) AddUnloadHook

AddUnloadHook adds a function to be called when the API spec is unloaded

func (s *APISpec) AddUnloadHook(hook func()) {
	s.unloadHooks = append(s.unloadHooks, hook)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*APISpec) CheckSpecMatchesStatus

CheckSpecMatchesStatus checks if a URL spec has a specific status. Deprecated: The function doesn't follow go return conventions (T, ok); use FindSpecMatchesStatus;

func (a *APISpec) CheckSpecMatchesStatus(r *http.Request, rxPaths []URLSpec, mode URLStatus) (bool, interface{}) {
	matchPath, method := a.getMatchPathAndMethod(r, mode)

	for i := range rxPaths {
		if rxPaths[i].Status != mode {
			continue
		}
		if !rxPaths[i].matchesMethod(method) {
			continue
		}
		if !rxPaths[i].matchesPath(matchPath, a) {
			continue
		}

		if spec, ok := rxPaths[i].modeSpecificSpec(mode); ok {
			return true, spec
		}
	}
	return false, nil
}

Cognitive complexity: 12, Cyclomatic complexity: 6

func (*APISpec) Expired

func (a *APISpec) Expired() bool {
	// Never expires
	if a.Expiration == "" || a.Expiration == "-1" {
		return false
	}

	// otherwise use parsed timestamp
	if a.ExpirationTs.IsZero() {
		log.Error("Could not parse expiration date, disallow")
		return true
	}

	return time.Since(a.ExpirationTs) >= 0
}

Cognitive complexity: 4, Cyclomatic complexity: 4

Uses: time.Since.

func (*APISpec) FindSpecMatchesStatus

FindSpecMatchesStatus checks if a URL spec has a specific status and returns the URLSpec for it.

func (a *APISpec) FindSpecMatchesStatus(r *http.Request, rxPaths []URLSpec, mode URLStatus) (*URLSpec, bool) {
	matchPath, method := a.getMatchPathAndMethod(r, mode)

	for i := range rxPaths {
		if rxPaths[i].Status != mode {
			continue
		}
		if !rxPaths[i].matchesMethod(method) {
			continue
		}
		if !rxPaths[i].matchesPath(matchPath, a) {
			continue
		}

		return &rxPaths[i], true
	}
	return nil, false
}

Cognitive complexity: 9, Cyclomatic complexity: 5

func (*APISpec) FireEvent

func (s *APISpec) FireEvent(name apidef.TykEvent, meta interface{}) {
	fireEvent(name, meta, s.EventPaths)
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*APISpec) GetSessionLifetimeRespectsKeyExpiration

GetSessionLifetimeRespectsKeyExpiration returns a boolean to tell whether session lifetime should respect to key expiration or not. The global config takes the precedence. If the global one is true, value of the one in api level doesn't matter.

func (a *APISpec) GetSessionLifetimeRespectsKeyExpiration() bool {
	if a.GlobalConfig.SessionLifetimeRespectsKeyExpiration {
		return true
	}

	return a.SessionLifetimeRespectsKeyExpiration
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*APISpec) Init

func (a *APISpec) Init(authStore, sessionStore, healthStore, orgStore storage.Handler) {
	a.AuthManager.Init(authStore)
	a.Health.Init(healthStore)
	a.OrgSessionManager.Init(orgStore)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*APISpec) RequestValid

RequestValid will check if an incoming request has valid version data and return a RequestStatus that describes the status of the request

func (a *APISpec) RequestValid(r *http.Request) (bool, RequestStatus) {
	versionInfo, status := a.Version(r)

	// Screwed up version info - fail and pass through
	if status != StatusOk {
		return false, status
	}

	// Load path data and whitelist data for version
	versionPaths, ok := a.RxPaths[versionInfo.Name]
	if !ok {
		log.Error("no RX Paths found for version ", versionInfo.Name)
		return false, VersionDoesNotExist
	}

	whiteListStatus, ok := a.WhiteListEnabled[versionInfo.Name]
	if !ok {
		log.Error("no whitelist data found")
		return false, VersionWhiteListStatusNotFound
	}

	if a.VersionData.NotVersioned && a.Expired() {
		return false, APIExpired
	} else if !a.VersionData.NotVersioned && versionInfo.Expired() {	// Deprecated
		return false, VersionExpired
	}

	// not expired, let's check path info
	status, _ = a.URLAllowedAndIgnored(r, versionPaths, whiteListStatus)
	switch status {
	case EndPointNotAllowed:
		return false, status
	case StatusRedirectFlowByReply:
		return true, status
	case StatusOkAndIgnore, StatusCached, StatusTransform,
		StatusHeaderInjected, StatusMethodTransformed:
		return true, status
	default:
		return true, StatusOk
	}
}

Cognitive complexity: 15, Cyclomatic complexity: 12

func (*APISpec) SanitizeProxyPaths

func (a *APISpec) SanitizeProxyPaths(r *http.Request) {
	if !a.Proxy.StripListenPath {
		return
	}

	log.Debug("Stripping proxy listen path: ", a.Proxy.ListenPath)

	r.URL.Path = a.StripListenPath(r.URL.Path)
	if r.URL.RawPath != "" {
		r.URL.RawPath = a.StripListenPath(r.URL.RawPath)
	}

	log.Debug("Upstream path is: ", r.URL.Path)
}

Cognitive complexity: 4, Cyclomatic complexity: 3

func (*APISpec) StopSessionManagerPool

func (a *APISpec) StopSessionManagerPool() {
	a.OrgSessionManager.Stop()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*APISpec) StripListenPath

StripListenPath will strip the listen path from the URL, keeping version in tact.

func (a *APISpec) StripListenPath(reqPath string) string {
	return httputil.StripListenPath(a.Proxy.ListenPath, reqPath)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: httputil.StripListenPath.

func (*APISpec) StripVersionPath

StripVersionPath will strip the version from the URL. The input URL should already have listen path stripped.

func (a *APISpec) StripVersionPath(reqPath string) string {
	// First part of the url is the version fragment
	part := strings.Split(strings.Trim(reqPath, "/"), "/")[0]

	matchesUrlVersioningPattern := true
	if a.VersionDefinition.UrlVersioningPattern != "" {
		re, err := regexp.Compile(a.VersionDefinition.UrlVersioningPattern)
		if err != nil {
			log.Error("Error compiling versioning pattern: ", err)
		} else {
			matchesUrlVersioningPattern = re.Match([]byte(part))
		}
	}

	if (a.VersionDefinition.StripVersioningData || a.VersionDefinition.StripPath) && matchesUrlVersioningPattern {
		return strings.Replace(reqPath, "/"+part+"/", "/", 1)
	}

	return reqPath
}

Cognitive complexity: 8, Cyclomatic complexity: 6

Uses: regexp.Compile, strings.Replace, strings.Split, strings.Trim.

func (*APISpec) URLAllowedAndIgnored

URLAllowedAndIgnored checks if a url is allowed and ignored.

func (a *APISpec) URLAllowedAndIgnored(r *http.Request, rxPaths []URLSpec, whiteListStatus bool) (RequestStatus, interface{}) {
	for i := range rxPaths {
		if !rxPaths[i].matchesPath(r.URL.Path, a) {
			continue
		}

		if r.Method == rxPaths[i].Internal.Method && rxPaths[i].Status == Internal && !ctxLoopingEnabled(r) {
			return EndPointNotAllowed, nil
		}
	}

	// Check if ignored
	for i := range rxPaths {
		if !rxPaths[i].matchesPath(r.URL.Path, a) {
			continue
		}

		if rxPaths[i].MethodActions == nil {
			switch rxPaths[i].Status {
			case WhiteList:
				if rxPaths[i].Whitelist.Method != "" {
					if rxPaths[i].Whitelist.Method != r.Method {
						continue
					}

					return a.getURLStatus(rxPaths[i].Status), nil
				}
			case BlackList:
				if rxPaths[i].Blacklist.Method != "" {
					if rxPaths[i].Blacklist.Method != r.Method {
						continue
					}

					return a.getURLStatus(rxPaths[i].Status), nil
				}
			case Ignored:
				if rxPaths[i].Ignored.Method != "" {
					if rxPaths[i].Ignored.Method != r.Method {
						continue
					}
				}

				return a.getURLStatus(rxPaths[i].Status), nil
			case MockResponse:
				if rxPaths[i].MockResponse.Method != r.Method {
					continue
				}

				return StatusRedirectFlowByReply, rxPaths[i].MockResponse
			}
		} else {	// Deprecated
			// We are using an extended path set, check for the method
			methodMeta, matchMethodOk := rxPaths[i].MethodActions[r.Method]
			if !matchMethodOk {
				continue
			}

			// Matched the method, check what status it is
			// TODO: Extend here for additional reply options
			switch methodMeta.Action {
			case apidef.NoAction:
				// NoAction status means we're not treating this request in any special or exceptional way
				return a.getURLStatus(rxPaths[i].Status), nil
			case apidef.Reply:
				return StatusRedirectFlowByReply, &methodMeta
			default:
				log.Error("URL Method Action was not set to NoAction, blocking.")
				return EndPointNotAllowed, nil
			}
		}

		if whiteListStatus {
			// We have a whitelist, nothing gets through unless specifically defined
			switch rxPaths[i].Status {
			case WhiteList, BlackList, Ignored:
			default:
				if rxPaths[i].Status == Internal && r.Method == rxPaths[i].Internal.Method && ctxLoopingEnabled(r) {
					return a.getURLStatus(rxPaths[i].Status), nil
				} else {
					return EndPointNotAllowed, nil
				}
			}
		}

		if rxPaths[i].TransformAction.Template != nil {
			return a.getURLStatus(rxPaths[i].Status), &rxPaths[i].TransformAction
		}

		if rxPaths[i].TransformJQAction.Filter != "" {
			return a.getURLStatus(rxPaths[i].Status), &rxPaths[i].TransformJQAction
		}

		// TODO: Fix, Not a great detection method
		if len(rxPaths[i].InjectHeaders.Path) > 0 {
			return a.getURLStatus(rxPaths[i].Status), &rxPaths[i].InjectHeaders
		}

		// Using a legacy path, handle it raw.
		return a.getURLStatus(rxPaths[i].Status), nil
	}

	// Nothing matched - should we still let it through?
	if whiteListStatus {
		// We have a whitelist, nothing gets through unless specifically defined
		return EndPointNotAllowed, nil
	}

	// No whitelist, but also not in any of the other lists, let it through and filter
	return StatusOk, nil
}

Cognitive complexity: 60, Cyclomatic complexity: 35

Uses: apidef.NoAction, apidef.Reply.

func (*APISpec) Unload

Release releases all resources associated with API spec

func (s *APISpec) Unload() {
	s.Lock()
	defer s.Unlock()

	// release circuit breaker resources
	for _, path := range s.RxPaths {
		for _, urlSpec := range path {
			if urlSpec.CircuitBreaker.CB != nil {
				// this will force CB-event reading Go-routine and subscriber Go-routine to exit
				urlSpec.CircuitBreaker.CB.Stop()
			}
		}
	}

	// cancel execution contexts
	if s.GraphEngine != nil {
		s.GraphEngine.Cancel()
	}

	// release all other resources associated with spec

	// JSVM object is a circular dependecy hell, but we can check if it initialized like this
	if s.JSVM.VM != nil {
		s.JSVM.DeInit()
	}

	if s.HTTPTransport != nil {
		// Prevent new idle connections to be generated.
		s.HTTPTransport.transport.DisableKeepAlives = true
		s.HTTPTransport.transport.CloseIdleConnections()
		s.HTTPTransport = nil
	}

	for _, hook := range s.unloadHooks {
		hook()
	}
	s.unloadHooks = nil
}

Cognitive complexity: 17, Cyclomatic complexity: 8

func (*APISpec) Validate

Validate returns nil if s is a valid spec and an error stating why the spec is not valid.

func (s *APISpec) Validate(oasConfig config.OASConfig) error {
	if s.IsOAS {
		err := s.OAS.Validate(context.Background(), oas.GetValidationOptionsFromConfig(oasConfig)...)
		if err != nil {
			return err
		}
	}

	// For tcp services we need to make sure we can bind to the port.
	switch s.Protocol {
	case "tcp", "tls":
		return s.validateTCP()
	default:
		return s.validateHTTP()
	}
}

Cognitive complexity: 7, Cyclomatic complexity: 5

Uses: context.Background, oas.GetValidationOptionsFromConfig.

func (*APISpec) Version

Version attempts to extract the version data from a request, depending on where it is stored in the request (currently only "header" is supported)

func (a *APISpec) Version(r *http.Request) (*apidef.VersionInfo, RequestStatus) {
	var version apidef.VersionInfo

	// try the context first
	if v := ctxGetVersionInfo(r); v != nil {
		version = *v
	} else {
		// Are we versioned?
		if a.VersionData.NotVersioned {
			// Get the first one in the list
			for _, v := range a.VersionData.Versions {
				version = v
				break
			}
		} else {
			// Extract Version Info
			// First checking for if default version is set
			vName := a.getVersionFromRequest(r)
			if vName == "" {
				if a.VersionData.DefaultVersion == "" {
					return &version, VersionNotFound
				}
				vName = a.VersionData.DefaultVersion
				ctxSetDefaultVersion(r)
			}
			// Load Version Data - General
			var ok bool
			if version, ok = a.VersionData.Versions[vName]; !ok {
				if a.VersionDefinition.FallbackToDefault {
					log.Debugf("fallback to default version: %s", a.VersionData.DefaultVersion)
					if version, ok = a.VersionData.Versions[a.VersionData.DefaultVersion]; ok {
						return &version, StatusOk
					}
				}

				return &version, VersionDoesNotExist
			}
		}

		// cache for the future
		ctxSetVersionInfo(r, &version)
	}

	return &version, StatusOk
}

Cognitive complexity: 21, Cyclomatic complexity: 9

Uses: apidef.VersionInfo.

func (*AccessRightsCheck) Name

func (a *AccessRightsCheck) Name() string {
	return "AccessRightsCheck"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*AccessRightsCheck) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (a *AccessRightsCheck) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	session := ctxGetSession(r)

	// If there's nothing in our profile, we let them through to the next phase
	if len(session.AccessRights) == 0 {
		return nil, http.StatusOK
	}

	// Otherwise, run auth checks
	versionList, apiExists := session.AccessRights[a.Spec.APIID]
	if !apiExists {
		a.Logger().Info("Attempted access to unauthorised API")
		return errors.New("Access to this API has been disallowed"), http.StatusForbidden
	}

	if a.Spec.VersionData.NotVersioned {
		return nil, http.StatusOK
	}

	targetVersion := a.Spec.getVersionFromRequest(r)
	if targetVersion == "" {
		targetVersion = a.Spec.VersionData.DefaultVersion
	}

	for _, vName := range versionList.Versions {
		if vName == targetVersion {
			return nil, http.StatusOK
		}
	}

	if a.Spec.VersionDefinition.FallbackToDefault && targetVersion != a.Spec.VersionData.DefaultVersion {
		for _, vName := range versionList.Versions {
			if vName == a.Spec.VersionData.DefaultVersion {
				return nil, http.StatusOK
			}
		}
	}

	a.Logger().Info("Attempted access to unauthorised API version.")
	return errors.New("Access to this API has been disallowed"), http.StatusForbidden
}

Cognitive complexity: 23, Cyclomatic complexity: 12

Uses: errors.New, http.StatusForbidden, http.StatusOK.

func (*AuthKey) Name

func (k *AuthKey) Name() string {
	return "AuthKey"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*AuthKey) ProcessRequest

func (k *AuthKey) ProcessRequest(_ http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	// skip auth key check if the request is looped.
	if ses := ctxGetSession(r); ses != nil && httpctx.IsSelfLooping(r) {
		return nil, http.StatusOK
	}

	key, authConfig := k.getAuthToken(k.getAuthType(), r)
	var certHash string

	keyExists := false
	var session user.SessionState
	updateSession := false
	if key != "" {
		key = stripBearer(key)
	} else if authConfig.UseCertificate && key == "" && r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
		log.Debug("Trying to find key by client certificate")
		certHash = k.Spec.OrgID + crypto.HexSHA256(r.TLS.PeerCertificates[0].Raw)
		if time.Now().After(r.TLS.PeerCertificates[0].NotAfter) {
			return errorAndStatusCode(ErrAuthCertExpired)
		}

		key = k.Gw.generateToken(k.Spec.OrgID, certHash)
	} else {
		k.Logger().Info("Attempted access with malformed header, no auth header found.")
		return errorAndStatusCode(ErrAuthAuthorizationFieldMissing)
	}

	session, keyExists = k.CheckSessionAndIdentityForValidKey(key, r)
	key = session.KeyID
	if !keyExists {
		// fallback to search by cert
		session, keyExists = k.CheckSessionAndIdentityForValidKey(certHash, r)
		if !keyExists {
			return k.reportInvalidKey(key, r, MsgNonExistentKey, ErrAuthKeyNotFound)
		}
	}

	if authConfig.UseCertificate {
		certLookup := session.Certificate

		if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
			certLookup = certHash
			if session.Certificate != certHash {
				session.Certificate = certHash
				updateSession = true
			}
		}

		if _, err := k.Gw.CertificateManager.GetRaw(certLookup); err != nil {
			return k.reportInvalidKey(key, r, MsgNonExistentCert, ErrAuthCertNotFound)
		}
	}

	// Set session state on context, we will need it later
	switch k.Spec.BaseIdentityProvidedBy {
	case apidef.AuthToken, apidef.UnsetAuth:
		hashKeys := k.Gw.GetConfig().HashKeys
		ctxSetSession(r, &session, updateSession, hashKeys)

		k.setContextVars(r, key)

		attributes := []otel.SpanAttribute{otel.APIKeyAliasAttribute(session.Alias)}

		if hashKeys {
			attributes = append(attributes, otel.APIKeyAttribute(session.KeyHash()))
		}

		ctxSetSpanAttributes(r, k.Name(), attributes...)
	}

	// Try using org-key format first:
	if strings.HasPrefix(key, session.OrgID) {
		err, statusCode := k.validateSignature(r, key[len(session.OrgID):])
		if err == nil && statusCode == http.StatusOK {
			return err, statusCode
		}
	}

	// As a second approach, try to use the internal ID that's part of the B64 JSON key:
	keyID, err := storage.TokenID(key)
	if err == nil {
		err, statusCode := k.validateSignature(r, keyID)
		if err == nil {
			return nil, statusCode
		}
	}

	// Last try is to take the key as is:
	return k.validateSignature(r, key)
}

Cognitive complexity: 39, Cyclomatic complexity: 25

Uses: apidef.AuthToken, apidef.UnsetAuth, crypto.HexSHA256, http.StatusOK, httpctx.IsSelfLooping, otel.APIKeyAliasAttribute, otel.APIKeyAttribute, otel.SpanAttribute, storage.TokenID, strings.HasPrefix, time.Now, user.SessionState.

func (*BaseExtractor) Error

Error is a helper for logging the extractor errors. It always returns HTTP 400 (so we don't expose any details).

func (e *BaseExtractor) Error(r *http.Request, err error, message string) (returnOverrides ReturnOverrides) {
	logEntry := e.Gw.getLogEntryForRequest(e.Logger(), r, "", nil)
	logEntry.Info("Extractor error: ", message, ", ", err)

	return ReturnOverrides{
		ResponseCode:	400,
		ResponseError:	"Authorization field missing",
	}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*BaseExtractor) ExtractAndCheck

ExtractAndCheck is called from the CP middleware, if ID extractor is enabled for the current API.

func (e *BaseExtractor) ExtractAndCheck(_ *http.Request) (sessionID string, returnOverrides ReturnOverrides) {
	log.WithFields(logrus.Fields{
		"prefix": "idextractor",
	}).Error("This extractor doesn't implement an extraction method, rejecting.")
	return "", ReturnOverrides{ResponseCode: 403, ResponseError: "Key not authorised"}
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: logrus.Fields.

func (*BaseExtractor) ExtractBody

ExtractBody is used when BodySource is specified.

func (e *BaseExtractor) ExtractBody(r *http.Request) (string, error) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return "", err
	}
	return string(body), err
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: ioutil.ReadAll.

func (*BaseExtractor) ExtractForm

ExtractForm is used when a FormSource is specified.

func (e *BaseExtractor) ExtractForm(r *http.Request, paramName string) (formValue string, err error) {
	parseForm(r)

	if paramName == "" {
		return "", errors.New("no form param name set")
	}

	values := r.Form[paramName]
	if len(values) == 0 {
		return "", errors.New("no form value")
	}

	return strings.Join(values, ""), nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: errors.New, strings.Join.

func (*BaseExtractor) ExtractHeader

ExtractHeader is used when a HeaderSource is specified.

func (e *BaseExtractor) ExtractHeader(r *http.Request) (headerValue string, err error) {
	headerName := e.IDExtractorConfig.HeaderName
	headerValue = r.Header.Get(headerName)
	if headerValue == "" {
		err = errors.New("bad header value")
	}
	return headerValue, err
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: errors.New.

func (*BaseExtractor) GenerateSessionID

GenerateSessionID is a helper for generating session IDs, it takes an input (usually the extractor output) and a middleware pointer.

func (e *BaseExtractor) GenerateSessionID(input string, mw *BaseMiddleware) (sessionID string) {
	data := []byte(input)
	tokenID := fmt.Sprintf("%x", md5.Sum(data))
	sessionID = e.Gw.generateToken(mw.Spec.OrgID, tokenID)
	return sessionID
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: fmt.Sprintf, md5.Sum.

func (*BaseMiddleware) ApplyPolicies

ApplyPolicies will check if any policies are loaded. If any are, it will overwrite the session state to use the policy values.

func (t *BaseMiddleware) ApplyPolicies(session *user.SessionState) error {
	var orgID *string
	if t.Spec != nil {
		orgID = &t.Spec.OrgID
	}
	store := policy.New(orgID, t.Gw, log)
	return store.Apply(session)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: policy.New.

func (*BaseMiddleware) Base

Base serves to provide the full BaseMiddleware API. It's part of the TykMiddleware interface. It escapes to a wider API surface than TykMiddleware, used by middlewares, etc.

func (t *BaseMiddleware) Base() *BaseMiddleware {
	return t
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BaseMiddleware) CheckSessionAndIdentityForValidKey

CheckSessionAndIdentityForValidKey will check first the Session store for a valid key, if not found, it will try the Auth Handler, if not found it will fail

func (t *BaseMiddleware) CheckSessionAndIdentityForValidKey(originalKey string, r *http.Request) (user.SessionState, bool) {
	key := originalKey
	minLength := t.Spec.GlobalConfig.MinTokenLength
	if minLength == 0 {
		// See https://github.com/TykTechnologies/tyk/issues/1681
		minLength = 3
	}

	if len(key) <= minLength {
		return user.SessionState{IsInactive: true}, false
	}

	// Try and get the session from the session store
	t.Logger().Debug("Querying local cache")
	keyHash := key
	cacheKey := key
	if t.Spec.GlobalConfig.HashKeys {
		cacheKey = storage.HashStr(key, storage.HashMurmur64)	// always hash cache keys with murmur64 to prevent collisions
	}

	// Check in-memory cache
	if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
		cachedVal, found := t.Gw.SessionCache.Get(cacheKey)
		if found {
			t.Logger().Debug("--> Key found in local cache")
			session := cachedVal.(user.SessionState).Clone()
			if err := t.ApplyPolicies(&session); err != nil {
				t.Logger().Error(err)
				return session, false
			}
			return session, true
		}
	}

	// Check session store
	t.Logger().Debug("Querying keystore")
	session, found := t.Gw.GlobalSessionManager.SessionDetail(t.Spec.OrgID, key, false)

	if found {
		if t.Spec.GlobalConfig.HashKeys {
			keyHash = storage.HashStr(session.KeyID)
		}
		session := session.Clone()
		session.SetKeyHash(keyHash)
		// If exists, assume it has been authorized and pass on
		// cache it
		if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
			t.Gw.SessionCache.Set(cacheKey, session, cache.DefaultExpiration)
		}

		// Check for a policy, if there is a policy, pull it and overwrite the session values
		if err := t.ApplyPolicies(&session); err != nil {
			t.Logger().Error(err)
			return session, false
		}
		t.Logger().Debug("Got key")
		return session, true
	}

	if _, ok := t.Spec.AuthManager.Store().(*RPCStorageHandler); ok && rpc.IsEmergencyMode() {
		return session.Clone(), false
	}

	// Only search in RPC if it's not in emergency mode
	t.Logger().Debug("Querying authstore")
	// 2. If not there, get it from the AuthorizationHandler
	session, found = t.Spec.AuthManager.SessionDetail(t.Spec.OrgID, key, false)
	if found {
		key = session.KeyID

		session := session.Clone()
		session.SetKeyHash(keyHash)
		// If not in Session, and got it from AuthHandler, create a session with a new TTL
		t.Logger().Info("Recreating session for key: ", t.Gw.obfuscateKey(key))

		// cache it
		if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
			go t.Gw.SessionCache.Set(cacheKey, session, cache.DefaultExpiration)
		}

		// Check for a policy, if there is a policy, pull it and overwrite the session values
		if err := t.ApplyPolicies(&session); err != nil {
			t.Logger().Error(err)
			return session, false
		}

		t.Logger().Debug("Lifetime is: ", session.Lifetime(t.Spec.GetSessionLifetimeRespectsKeyExpiration(), t.Spec.SessionLifetime, t.Gw.GetConfig().ForceGlobalSessionLifetime, t.Gw.GetConfig().GlobalSessionLifetime))

		session.Touch()

		return session, found
	}

	// session not found
	session.KeyID = key
	return session, false
}

Cognitive complexity: 29, Cyclomatic complexity: 16

Uses: cache.DefaultExpiration, rpc.IsEmergencyMode, storage.HashMurmur64, storage.HashStr, user.SessionState.

func (*BaseMiddleware) Config

func (t *BaseMiddleware) Config() (interface{}, error) {
	return nil, nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*BaseMiddleware) Copy

Copy provides a new BaseMiddleware with it's own logger scope (copy). The Spec, Proxy and Gw values are not copied.

func (m *BaseMiddleware) Copy() *BaseMiddleware {
	return &BaseMiddleware{
		logger:	m.logger.Dup(),
		Spec:	m.Spec,
		Proxy:	m.Proxy,
		Gw:	m.Gw,
	}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*BaseMiddleware) EnabledForSpec

func (t *BaseMiddleware) EnabledForSpec() bool {
	return true
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BaseMiddleware) FireEvent

FireEvent is added to the BaseMiddleware object so it is available across the entire stack

func (t *BaseMiddleware) FireEvent(name apidef.TykEvent, meta interface{}) {
	fireEvent(name, meta, t.Spec.EventPaths)
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*BaseMiddleware) GetSpec

GetSpec returns the spec of the middleware

func (t *BaseMiddleware) GetSpec() *APISpec {
	return t.Spec
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BaseMiddleware) Init

func (t *BaseMiddleware) Init()	{}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BaseMiddleware) Logger

Logger is used by middleware process functions.

func (t *BaseMiddleware) Logger() (logger *logrus.Entry) {
	t.loggerMu.Lock()
	defer t.loggerMu.Unlock()

	if t.logger == nil {
		t.logger = logrus.NewEntry(log)
	}
	return t.logger
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: logrus.NewEntry.

func (*BaseMiddleware) OrgSession

func (t *BaseMiddleware) OrgSession(orgID string) (user.SessionState, bool) {

	if rpc.IsEmergencyMode() {
		return user.SessionState{}, false
	}

	// Try and get the session from the session store
	session, found := t.Spec.OrgSessionManager.SessionDetail(orgID, orgID, false)
	if found && t.Spec.GlobalConfig.EnforceOrgDataAge {
		// If exists, assume it has been authorized and pass on
		// We cache org expiry data
		t.Logger().Debug("Setting data expiry: ", orgID)

		t.Gw.ExpiryCache.Set(session.OrgID, session.DataExpires, cache.DefaultExpiration)
	}

	session.SetKeyHash(storage.HashKey(orgID, t.Gw.GetConfig().HashKeys))

	return session.Clone(), found
}

Cognitive complexity: 5, Cyclomatic complexity: 4

Uses: cache.DefaultExpiration, rpc.IsEmergencyMode, storage.HashKey, user.SessionState.

func (*BaseMiddleware) OrgSessionExpiry

func (t *BaseMiddleware) OrgSessionExpiry(orgid string) int64 {
	t.Logger().Debug("Checking: ", orgid)

	// Cache failed attempt
	id, err, _ := orgSessionExpiryCache.Do(orgid, func() (interface{}, error) {
		cachedVal, found := t.Gw.ExpiryCache.Get(orgid)
		if found {
			return cachedVal, nil
		}

		s, found := t.OrgSession(orgid)
		if found && t.Spec.GlobalConfig.EnforceOrgDataAge {
			return s.DataExpires, nil
		}
		return 0, errors.New("missing session")
	})

	if err != nil {
		t.Logger().Debug("no cached entry found, returning 7 days")
		t.SetOrgExpiry(orgid, DEFAULT_ORG_SESSION_EXPIRATION)
		return DEFAULT_ORG_SESSION_EXPIRATION
	}

	return id.(int64)
}

Cognitive complexity: 8, Cyclomatic complexity: 5

Uses: errors.New.

func (*BaseMiddleware) RecordAccessLog

RecordAccessLog is used for Success/Error handler logging. It emits a log entry with populated access log fields.

func (t *BaseMiddleware) RecordAccessLog(req *http.Request, resp *http.Response, latency analytics.Latency) {
	if !t.Spec.GlobalConfig.AccessLogs.Enabled {
		return
	}

	gw := t.Gw
	gwConfig := gw.GetConfig()

	hashKeys := gwConfig.HashKeys
	allowedFields := gwConfig.AccessLogs.Template

	// Set the access log fields
	accessLog := accesslog.NewRecord()
	accessLog.WithApiKey(req, hashKeys, gw.obfuscateKey)
	accessLog.WithRequest(req, latency)
	accessLog.WithResponse(resp)

	logFields := accessLog.Fields(allowedFields)

	t.Logger().WithFields(logFields).Info()
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: accesslog.NewRecord.

func (*BaseMiddleware) SetName

func (t *BaseMiddleware) SetName(name string) {
	t.loggerMu.Lock()
	defer t.loggerMu.Unlock()

	if t.logger == nil {
		t.logger = logrus.NewEntry(log)
	}
	t.logger = t.logger.WithField("mw", name)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: logrus.NewEntry.

func (*BaseMiddleware) SetOrgExpiry

func (t *BaseMiddleware) SetOrgExpiry(orgid string, expiry int64) {
	t.Gw.ExpiryCache.Set(orgid, expiry, cache.DefaultExpiration)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: cache.DefaultExpiration.

func (*BaseMiddleware) SetRequestLogger

func (t *BaseMiddleware) SetRequestLogger(r *http.Request) *logrus.Entry {
	t.loggerMu.Lock()
	defer t.loggerMu.Unlock()

	if t.logger == nil {
		t.logger = logrus.NewEntry(log)
	}
	t.logger = t.Gw.getLogEntryForRequest(t.logger, r, ctxGetAuthToken(r), nil)
	return t.logger
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: logrus.NewEntry.

func (*BaseMiddleware) Unload

Unload unloads the middleware and frees resources

func (t *BaseMiddleware) Unload() {
	// methos created to satisfy middleware contract
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BaseMiddleware) UpdateRequestSession

func (t *BaseMiddleware) UpdateRequestSession(r *http.Request) bool {
	session := ctxGetSession(r)
	token := ctxGetAuthToken(r)

	if session == nil || token == "" {
		return false
	}

	if !session.IsModified() {
		return false
	}

	lifetime := session.Lifetime(t.Spec.GetSessionLifetimeRespectsKeyExpiration(), t.Spec.SessionLifetime, t.Gw.GetConfig().ForceGlobalSessionLifetime, t.Gw.GetConfig().GlobalSessionLifetime)
	if err := t.Gw.GlobalSessionManager.UpdateSession(token, session, lifetime, false); err != nil {
		t.Logger().WithError(err).Error("Can't update session")
		return false
	}

	// Reset session state, useful for benchmarks when request object stays the same.
	session.Reset()

	if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
		t.Gw.SessionCache.Set(session.KeyHash(), session.Clone(), cache.DefaultExpiration)
	}

	return true
}

Cognitive complexity: 8, Cyclomatic complexity: 6

Uses: cache.DefaultExpiration.

func (*BaseTykResponseHandler) Enabled

func (b *BaseTykResponseHandler) Enabled() bool {
	return true
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BaseTykResponseHandler) HandleError

func (b *BaseTykResponseHandler) HandleError(writer http.ResponseWriter, h *http.Request)	{}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BaseTykResponseHandler) HandleResponse

func (b *BaseTykResponseHandler) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error {
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BaseTykResponseHandler) Init

func (b *BaseTykResponseHandler) Init(i interface{}, spec *APISpec) error {
	return nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*BaseTykResponseHandler) Name

func (b *BaseTykResponseHandler) Name() string {
	return "BaseTykResponseHandler"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BasicAuthKeyIsValid) EnabledForSpec

EnabledForSpec checks if UseBasicAuth is set in the API definition.

func (k *BasicAuthKeyIsValid) EnabledForSpec() bool {
	if !k.Spec.UseBasicAuth {
		return false
	}

	var err error

	if k.Spec.BasicAuth.ExtractFromBody {
		if k.Spec.BasicAuth.BodyUserRegexp == "" || k.Spec.BasicAuth.BodyPasswordRegexp == "" {
			k.Logger().Error("Basic Auth configured to extract credentials from body, but regexps are empty")
			return false
		}

		k.bodyUserRegexp, err = regexp.Compile(k.Spec.BasicAuth.BodyUserRegexp)
		if err != nil {
			k.Logger().WithError(err).Error("Invalid user body regexp")
			return false
		}

		k.bodyPasswordRegexp, err = regexp.Compile(k.Spec.BasicAuth.BodyPasswordRegexp)
		if err != nil {
			k.Logger().WithError(err).Error("Invalid user password regexp")
			return false
		}
	}

	return true
}

Cognitive complexity: 10, Cyclomatic complexity: 7

Uses: regexp.Compile.

func (*BasicAuthKeyIsValid) Name

func (k *BasicAuthKeyIsValid) Name() string {
	return "BasicAuthKeyIsValid"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*BasicAuthKeyIsValid) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (k *BasicAuthKeyIsValid) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	username, password, err, code := k.basicAuthHeaderCredentials(w, r)
	token := r.Header.Get(header.Authorization)
	if err != nil {
		if k.Spec.BasicAuth.ExtractFromBody {
			w.Header().Del(header.WWWAuthenticate)
			username, password, err, code = k.basicAuthBodyCredentials(w, r)
		} else {
			k.Logger().Warn("Attempted access with malformed header, no auth header found.")
		}

		if err != nil {
			return err, code
		}
	}

	// Check if API key valid
	keyName := username
	logger := k.Logger().WithField("key", k.Gw.obfuscateKey(keyName))
	session, keyExists := k.CheckSessionAndIdentityForValidKey(keyName, r)
	keyName = session.KeyID

	if !keyExists {
		if k.Gw.GetConfig().HashKeyFunction == "" {
			logger.Warning("Attempted access with non-existent user.")
			return k.handleAuthFail(w, r, token)
		} else {	// check for key with legacy format "org_id" + "user_name"
			logger.Info("Could not find user, falling back to legacy format key.")
			legacyKeyName := strings.TrimPrefix(username, k.Spec.OrgID)
			keyName, _ = storage.GenerateToken(k.Spec.OrgID, legacyKeyName, "")
			session, keyExists = k.CheckSessionAndIdentityForValidKey(keyName, r)
			keyName = session.KeyID
			if !keyExists {
				logger.Warning("Attempted access with non-existent user.")
				return k.handleAuthFail(w, r, token)
			}
		}
	}

	if err := k.checkPassword(&session, password, logger); err != nil {
		logger.WithError(err).Warn("Attempted access with existing user, failed password check.")
		return k.handleAuthFail(w, r, token)
	}

	// Set session state on context, we will need it later
	switch k.Spec.BaseIdentityProvidedBy {
	case apidef.BasicAuthUser, apidef.UnsetAuth:
		ctxSetSession(r, &session, false, k.Gw.GetConfig().HashKeys)
	}

	return nil, http.StatusOK
}

Cognitive complexity: 24, Cyclomatic complexity: 11

Uses: apidef.BasicAuthUser, apidef.UnsetAuth, header.Authorization, header.WWWAuthenticate, http.StatusOK, storage.GenerateToken, strings.TrimPrefix.

func (*BatchRequestHandler) ConstructRequests

func (b *BatchRequestHandler) ConstructRequests(batchRequest BatchRequestStructure, unsafe bool) ([]*http.Request, error) {
	requestSet := []*http.Request{}

	ignoreCanonical := b.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
	for i, requestDef := range batchRequest.Requests {
		// We re-build the URL to ensure that the requested URL is actually for the API in question
		// URLs need to be built absolute so they go through the rate limiting and request limiting machinery
		var absURL string
		if !unsafe {
			absUrlHeader := "http://localhost:" + strconv.Itoa(b.Gw.GetConfig().ListenPort)
			absURL = strings.Join([]string{absUrlHeader, strings.Trim(b.API.Proxy.ListenPath, "/"), requestDef.RelativeURL}, "/")
		} else {
			absURL = requestDef.RelativeURL
		}

		request, err := http.NewRequest(requestDef.Method, absURL, strings.NewReader(requestDef.Body))
		if err != nil {
			log.Error("Failure generating batch request for request spec index: ", i)
			return nil, err
		}

		// Add headers
		for k, v := range requestDef.Headers {
			setCustomHeader(request.Header, k, v, ignoreCanonical)
		}
		requestSet = append(requestSet, request)
	}

	return requestSet, nil
}

Cognitive complexity: 10, Cyclomatic complexity: 5

Uses: http.NewRequest, http.Request, strconv.Itoa, strings.Join, strings.NewReader, strings.Trim.

func (*BatchRequestHandler) DecodeBatchRequest

func (b *BatchRequestHandler) DecodeBatchRequest(r *http.Request) (BatchRequestStructure, error) {
	var batchRequest BatchRequestStructure
	err := json.NewDecoder(r.Body).Decode(&batchRequest)
	return batchRequest, err
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: json.NewDecoder.

func (*BatchRequestHandler) HandleBatchRequest

HandleBatchRequest is the actual http handler for a batch request on an API definition

func (b *BatchRequestHandler) HandleBatchRequest(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		return
	}

	// Decode request
	batchRequest, err := b.DecodeBatchRequest(r)
	if err != nil {
		log.Error("Could not decode batch request, decoding failed: ", err)
		doJSONWrite(w, http.StatusBadRequest, apiError("Batch request malformed"))
		return
	}

	// Construct the requests
	requestSet, err := b.ConstructRequests(batchRequest, false)
	if err != nil {
		doJSONWrite(w, http.StatusBadRequest, apiError(fmt.Sprintf("Batch request creation failed , request structure malformed")))
		return
	}

	// Run requests and collate responses
	replySet := b.MakeRequests(batchRequest, requestSet)

	// Respond
	doJSONWrite(w, http.StatusOK, replySet)
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: fmt.Sprintf, http.StatusBadRequest, http.StatusOK.

func (*BatchRequestHandler) MakeRequests

func (b *BatchRequestHandler) MakeRequests(batchRequest BatchRequestStructure, requestSet []*http.Request) []BatchReplyUnit {
	replySet := []BatchReplyUnit{}

	if len(batchRequest.Requests) != len(requestSet) {
		log.Error("Something went wrong creating requests, they are of mismatched lengths!", len(batchRequest.Requests), len(requestSet))
	}

	if !batchRequest.SuppressParallelExecution {
		replies := make(chan BatchReplyUnit)
		for i, req := range requestSet {
			go func(i int, req *http.Request) {
				reply := b.doRequest(req, batchRequest.Requests[i].RelativeURL)
				replies <- reply
			}(i, req)
		}

		for range batchRequest.Requests {
			replySet = append(replySet, <-replies)
		}
	} else {
		for i, req := range requestSet {
			reply := b.doRequest(req, batchRequest.Requests[i].RelativeURL)
			replySet = append(replySet, reply)
		}
	}

	return replySet
}

Cognitive complexity: 17, Cyclomatic complexity: 6

Uses: http.Request.

func (*BatchRequestHandler) ManualBatchRequest

HandleBatchRequest is the actual http handler for a batch request on an API definition

func (b *BatchRequestHandler) ManualBatchRequest(requestObject []byte) ([]byte, error) {
	// Decode request
	var batchRequest BatchRequestStructure
	if err := json.Unmarshal(requestObject, &batchRequest); err != nil {
		return nil, fmt.Errorf("could not decode batch request, decoding failed: %w", err)
	}

	// Construct the unsafe requests
	requestSet, err := b.ConstructRequests(batchRequest, true)
	if err != nil {
		return nil, fmt.Errorf("batch request creation failed , request structure malformed: %w", err)
	}

	// Run requests and collate responses
	replySet := b.MakeRequests(batchRequest, requestSet)

	// Encode responses
	replyMessage, err := json.Marshal(&replySet)
	if err != nil {
		return nil, fmt.Errorf("couldn't encode response to string: %w", err)
	}

	return replyMessage, nil
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: fmt.Errorf, json.Marshal, json.Unmarshal.

func (*Bundle) AddToSpec

AddToSpec attaches the custom middleware settings to an API definition.

func (b *Bundle) AddToSpec() {
	b.Spec.CustomMiddleware = b.Manifest.CustomMiddleware

	// Load Python interpreter if the
	if loadedDrivers[b.Spec.CustomMiddleware.Driver] == nil && b.Spec.CustomMiddleware.Driver == apidef.PythonDriver {
		var err error
		loadedDrivers[apidef.PythonDriver], err = NewPythonDispatcher(b.Gw.GetConfig())
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix": "coprocess",
			}).WithError(err).Error("Couldn't load Python dispatcher")
			return
		}
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Info("Python dispatcher was initialized")
	}
	dispatcher := loadedDrivers[b.Spec.CustomMiddleware.Driver]
	if dispatcher != nil {
		dispatcher.HandleMiddlewareCache(&b.Manifest, b.Path)
	}
}

Cognitive complexity: 8, Cyclomatic complexity: 5

Uses: apidef.PythonDriver, logrus.Fields.

func (*Bundle) Verify

Verify performs a signature verification on the bundle file.

func (b *Bundle) Verify() error {
	log.WithFields(logrus.Fields{
		"prefix": "main",
	}).Info("----> Verifying bundle: ", b.Spec.CustomMiddlewareBundle)

	var useSignature = b.Gw.GetConfig().PublicKeyPath != ""

	var (
		verifier	goverify.Verifier
		err		error
	)

	if useSignature {
		// Perform signature verification if a public key path is set:
		if b.Manifest.Signature == "" {
			// Error: A public key is set, but the bundle isn't signed.
			return errors.New("Bundle isn't signed")
		}
		verifier, err = b.Gw.SignatureVerifier()
		if err != nil {
			return err
		}
	}

	var bundleData bytes.Buffer

	for _, f := range b.Manifest.FileList {
		extractedPath := filepath.Join(b.Path, f)

		f, err := os.Open(extractedPath)
		if err != nil {
			return err
		}
		_, err = io.Copy(&bundleData, f)
		f.Close()
		if err != nil {
			return err
		}
	}

	checksum := fmt.Sprintf("%x", md5.Sum(bundleData.Bytes()))
	if checksum != b.Manifest.Checksum {
		return errors.New("Invalid checksum")
	}

	if useSignature {
		signed, err := base64.StdEncoding.DecodeString(b.Manifest.Signature)
		if err != nil {
			return err
		}
		return verifier.Verify(bundleData.Bytes(), signed)
	}
	return nil
}

Cognitive complexity: 20, Cyclomatic complexity: 10

Uses: base64.StdEncoding, bytes.Buffer, errors.New, filepath.Join, fmt.Sprintf, goverify.Verifier, io.Copy, logrus.Fields, md5.Sum, os.Open.

func (*CertificateCheckMW) EnabledForSpec

func (m *CertificateCheckMW) EnabledForSpec() bool {
	return m.Spec.UseMutualTLSAuth
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*CertificateCheckMW) Name

func (m *CertificateCheckMW) Name() string {
	return "CertificateCheckMW"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*CertificateCheckMW) ProcessRequest

func (m *CertificateCheckMW) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	if m.Spec.UseMutualTLSAuth {
		certIDs := append(m.Spec.ClientCertificates, m.Spec.GlobalConfig.Security.Certificates.API...)
		apiCerts := m.Gw.CertificateManager.List(certIDs, certs.CertificatePublic)
		if err := crypto.ValidateRequestCerts(r, apiCerts); err != nil {
			return err, http.StatusForbidden
		}
	}
	return nil, http.StatusOK
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: certs.CertificatePublic, crypto.ValidateRequestCerts, http.StatusForbidden, http.StatusOK.

func (*CoProcessEventHandler) HandleEvent

func (l *CoProcessEventHandler) HandleEvent(em config.EventMessage) {
	dispatcher := loadedDrivers[l.Spec.CustomMiddleware.Driver]
	if dispatcher == nil {
		return
	}
	eventWrapper := CoProcessEventWrapper{
		Event:		em,
		Handler:	l.methodName,
		SpecJSON:	&l.SpecJSON,
	}

	// JSON-encode the event data object
	msgAsJSON, err := json.Marshal(eventWrapper)
	if err != nil {
		log.Error("Failed to encode event data: ", err)
		return
	}
	dispatcher.DispatchEvent(msgAsJSON)
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: json.Marshal.

func (*CoProcessEventHandler) Init

func (l *CoProcessEventHandler) Init(handlerConf interface{}) error {
	l.methodName = handlerConf.(map[string]interface{})["name"].(string)

	// Set the VM globals
	globalVals := JSVMContextGlobal{
		APIID:	l.Spec.APIID,
		OrgID:	l.Spec.OrgID,
	}

	gValAsJSON, err := json.Marshal(globalVals)
	if err != nil {
		return fmt.Errorf("failed to marshal globals: %w", err)
	}

	l.SpecJSON = json.RawMessage(gValAsJSON)
	return nil
}

Cognitive complexity: 5, Cyclomatic complexity: 2

Uses: fmt.Errorf, json.Marshal, json.RawMessage.

func (*CoProcessMiddleware) EnabledForSpec

EnabledForSpec checks if this middleware should be enabled for a given API.

func (m *CoProcessMiddleware) EnabledForSpec() bool {

	if !m.Gw.GetConfig().CoProcessOptions.EnableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error("Your API specifies a CP custom middleware, either Tyk wasn't build with CP support or CP is not enabled in your Tyk configuration file!")
		return false
	}

	var supported bool
	for _, driver := range supportedDrivers {
		if m.Spec.CustomMiddleware.Driver == driver {
			supported = true
		}
	}

	if !supported {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Errorf("Unsupported driver '%s'", m.Spec.CustomMiddleware.Driver)
		return false
	}

	if d, _ := loadedDrivers[m.Spec.CustomMiddleware.Driver]; d == nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Errorf("Driver '%s' isn't loaded", m.Spec.CustomMiddleware.Driver)
		return false
	}

	log.WithFields(logrus.Fields{
		"prefix": "coprocess",
	}).Debug("Enabling CP middleware.")
	m.successHandler = &SuccessHandler{m.BaseMiddleware.Copy()}
	return true
}

Cognitive complexity: 16, Cyclomatic complexity: 6

Uses: logrus.Fields.

func (*CoProcessMiddleware) Name

func (m *CoProcessMiddleware) Name() string {
	return "CoProcessMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*CoProcessMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (m *CoProcessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if m.HookType == coprocess.HookType_CustomKeyCheck {
		if ctxGetRequestStatus(r) == StatusOkAndIgnore {
			return nil, http.StatusOK
		}
	}

	logger := m.Logger()
	logger.Debug("CoProcess Request, HookType: ", m.HookType)
	originalURL := r.URL
	authToken, _ := m.getAuthToken(apidef.CoprocessType, r)

	extractor := getIDExtractor(m.Spec)

	var returnOverrides ReturnOverrides
	var sessionID string

	if m.HookType == coprocess.HookType_CustomKeyCheck && extractor != nil {
		sessionID, returnOverrides = extractor.ExtractAndCheck(r)
		if returnOverrides.ResponseCode != 0 {
			if returnOverrides.ResponseError == "" {
				return nil, returnOverrides.ResponseCode
			}
			err := errors.New(returnOverrides.ResponseError)
			return err, returnOverrides.ResponseCode
		}
	}

	coProcessor := CoProcessor{
		Middleware: m,
	}

	object, err := coProcessor.BuildObject(r, nil, m.Spec)
	if err != nil {
		logger.WithError(err).Error("Failed to build request object")
		return errors.New("Middleware error"), 500
	}

	var origURL string
	if rewriteUrl := ctxGetURLRewriteTarget(r); rewriteUrl != nil {
		origURL = object.Request.Url
		object.Request.Url = rewriteUrl.String()
		object.Request.RequestUri = rewriteUrl.RequestURI()
	}

	var origMethod string
	if transformMethod := ctxGetTransformRequestMethod(r); transformMethod != "" {
		origMethod = r.Method
		object.Request.Method = transformMethod
	}

	t1 := time.Now()
	returnObject, err := coProcessor.Dispatch(object)
	ms := DurationToMillisecond(time.Since(t1))

	if err != nil {
		logger.WithError(err).Error("Dispatch error")
		if m.HookType == coprocess.HookType_CustomKeyCheck {
			return errors.New("Key not authorised"), 403
		} else {
			return errors.New("Middleware error"), 500
		}
	}

	m.logger.WithField("ms", ms).Debug("gRPC request processing took")

	err = coProcessor.ObjectPostProcess(returnObject, r, origURL, origMethod)
	if err != nil {
		// Restore original URL object so that it can be used by ErrorHandler:
		r.URL = originalURL
		logger.WithError(err).Error("Failed to post-process request object")
		return errors.New("Middleware error"), 500
	}

	var token string
	if returnObject.Session != nil {
		// For compatibility purposes, inject coprocess.Object.Metadata fields:
		if returnObject.Metadata != nil {
			if returnObject.Session.Metadata == nil {
				returnObject.Session.Metadata = make(map[string]string)
			}
			for k, v := range returnObject.Metadata {
				returnObject.Session.Metadata[k] = v
			}
		}

		token = returnObject.Session.Metadata["token"]
	}

	if returnObject.Request.ReturnOverrides.ResponseError != "" {
		returnObject.Request.ReturnOverrides.ResponseBody = returnObject.Request.ReturnOverrides.ResponseError
	}

	// The CP middleware indicates this is a bad auth:
	if returnObject.Request.ReturnOverrides.ResponseCode >= http.StatusBadRequest && !returnObject.Request.ReturnOverrides.OverrideError {
		logger.WithField("key", m.Gw.obfuscateKey(token)).Info("Attempted access with invalid key")

		for h, v := range returnObject.Request.ReturnOverrides.Headers {
			w.Header().Set(h, v)
		}

		// Fire Authfailed Event
		AuthFailed(m, r, token)

		// Report in health check
		reportHealthValue(m.Spec, KeyFailure, "1")

		errorMsg := "Key not authorised"
		if returnObject.Request.ReturnOverrides.ResponseBody != "" {
			errorMsg = returnObject.Request.ReturnOverrides.ResponseBody
		}

		return errors.New(errorMsg), int(returnObject.Request.ReturnOverrides.ResponseCode)
	}

	if returnObject.Request.ReturnOverrides.ResponseCode > 0 {
		for h, v := range returnObject.Request.ReturnOverrides.Headers {
			w.Header().Set(h, v)
		}
		w.WriteHeader(int(returnObject.Request.ReturnOverrides.ResponseCode))
		w.Write([]byte(returnObject.Request.ReturnOverrides.ResponseBody))

		// Record analytics data:
		res := new(http.Response)
		res.Proto = "HTTP/1.0"
		res.ProtoMajor = 1
		res.ProtoMinor = 0
		res.StatusCode = int(returnObject.Request.ReturnOverrides.ResponseCode)
		res.Body = nopCloser{
			ReadSeeker: strings.NewReader(returnObject.Request.ReturnOverrides.ResponseBody),
		}
		res.ContentLength = int64(len(returnObject.Request.ReturnOverrides.ResponseBody))
		m.successHandler.RecordHit(r, analytics.Latency(analytics.Latency{Total: int64(ms)}), int(returnObject.Request.ReturnOverrides.ResponseCode), res, false)
		return nil, mwStatusRespond
	}

	// Is this a CP authentication middleware?
	if coprocessAuthEnabled(m.Spec) && m.HookType == coprocess.HookType_CustomKeyCheck {
		if extractor == nil {
			sessionID = token
		}

		// The CP middleware didn't setup a session:
		if returnObject.Session == nil || token == "" {
			authHeaderValue, _ := m.getAuthToken(m.getAuthType(), r)
			AuthFailed(m, r, authHeaderValue)
			return errors.New(http.StatusText(http.StatusForbidden)), http.StatusForbidden
		}

		returnedSession := TykSessionState(returnObject.Session)

		// If the returned object contains metadata, add them to the session:
		for k, v := range returnObject.Metadata {
			returnedSession.MetaData[k] = string(v)
		}

		returnedSession.OrgID = m.Spec.OrgID
		// set a Key ID as default
		returnedSession.KeyID = token

		if err := m.ApplyPolicies(returnedSession); err != nil {
			AuthFailed(m, r, authToken)
			return errors.New(http.StatusText(http.StatusForbidden)), http.StatusForbidden
		}

		existingSession, found := m.Gw.GlobalSessionManager.SessionDetail(m.Spec.OrgID, sessionID, false)
		if found {
			returnedSession.QuotaRenews = existingSession.QuotaRenews
			returnedSession.QuotaRemaining = existingSession.QuotaRemaining

			for api := range returnedSession.AccessRights {
				if _, found := existingSession.AccessRights[api]; found {
					if !returnedSession.AccessRights[api].Limit.IsEmpty() {
						ar := returnedSession.AccessRights[api]
						ar.Limit.QuotaRenews = existingSession.AccessRights[api].Limit.QuotaRenews
						ar.Limit.QuotaRemaining = existingSession.AccessRights[api].Limit.QuotaRemaining
						returnedSession.AccessRights[api] = ar
					}
				}
			}
		}

		// Apply it second time to fix the quota
		if err := m.ApplyPolicies(returnedSession); err != nil {
			AuthFailed(m, r, authToken)
			return errors.New(http.StatusText(http.StatusForbidden)), http.StatusForbidden
		}

		returnedSession.KeyID = sessionID

		switch m.Spec.BaseIdentityProvidedBy {
		case apidef.CustomAuth, apidef.UnsetAuth:
			ctxSetSession(r, returnedSession, true, m.Gw.GetConfig().HashKeys)
		}
	}

	return nil, http.StatusOK
}

Cognitive complexity: 76, Cyclomatic complexity: 38

Uses: analytics.Latency, apidef.CoprocessType, apidef.CustomAuth, apidef.UnsetAuth, coprocess.HookType_CustomKeyCheck, errors.New, http.Response, http.StatusBadRequest, http.StatusForbidden, http.StatusOK, http.StatusText, strings.NewReader, time.Now, time.Since.

func (*CoProcessor) BuildObject

BuildObject constructs a CoProcessObject from a given http.Request.

func (c *CoProcessor) BuildObject(req *http.Request, res *http.Response, spec *APISpec) (*coprocess.Object, error) {
	headers := ProtoMap(req.Header)

	host := req.Host
	if host == "" && req.URL != nil {
		host = req.URL.Host
	}
	if host != "" {
		headers["Host"] = host
	}
	scheme := "http"
	if req.TLS != nil {
		scheme = "https"
	}
	miniRequestObject := &coprocess.MiniRequestObject{
		Headers:	headers,
		SetHeaders:	map[string]string{},
		DeleteHeaders:	[]string{},
		Url:		req.URL.String(),
		Params:		ProtoMap(req.URL.Query()),
		AddParams:	map[string]string{},
		ExtendedParams:	ProtoMap(nil),
		DeleteParams:	[]string{},
		ReturnOverrides: &coprocess.ReturnOverrides{
			ResponseCode: -1,
		},
		Method:		req.Method,
		RequestUri:	req.RequestURI,
		Scheme:		scheme,
	}

	if req.Body != nil {
		defer req.Body.Close()
		var err error
		miniRequestObject.RawBody, err = ioutil.ReadAll(req.Body)
		if err != nil {
			return nil, err
		}
		if utf8.Valid(miniRequestObject.RawBody) && !c.Middleware.RawBodyOnly {
			miniRequestObject.Body = string(miniRequestObject.RawBody)
		}
	}

	object := &coprocess.Object{
		Request:	miniRequestObject,
		HookName:	c.Middleware.HookName,
		HookType:	c.Middleware.HookType,
	}

	object.Spec = make(map[string]string)

	// Append spec data:
	if c.Middleware != nil {
		configDataAsJSON := []byte("{}")
		if shouldAddConfigData(c.Middleware.Spec) {
			var err error
			configDataAsJSON, err = json.Marshal(c.Middleware.Spec.ConfigData)
			if err != nil {
				return nil, err
			}
		}

		bundleHash, err := c.Middleware.Gw.getHashedBundleName(spec.CustomMiddlewareBundle)
		if err != nil {
			return nil, err
		}

		object.Spec = map[string]string{
			"OrgID":	c.Middleware.Spec.OrgID,
			"APIID":	c.Middleware.Spec.APIID,
			"bundle_hash":	bundleHash,
		}

		if shouldAddConfigData(c.Middleware.Spec) {
			object.Spec["config_data"] = string(configDataAsJSON)
		}
	}

	// Encode the session object (if not a pre-process & not a custom key check):
	if object.HookType != coprocess.HookType_Pre && object.HookType != coprocess.HookType_CustomKeyCheck {
		if session := ctxGetSession(req); session != nil {
			object.Session = ProtoSessionState(session)
			// For compatibility purposes:
			object.Metadata = object.Session.Metadata
		}
	}

	// Append response data if it's available:
	if res != nil {
		resObj := &coprocess.ResponseObject{
			Headers: make(map[string]string, len(res.Header)),
		}
		for k, v := range res.Header {
			// set univalue header
			resObj.Headers[k] = v[0]

			// set multivalue header
			currentHeader := coprocess.Header{
				Key:	k,
				Values:	v,
			}
			resObj.MultivalueHeaders = append(resObj.MultivalueHeaders, &currentHeader)
		}
		resObj.StatusCode = int32(res.StatusCode)
		rawBody, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return nil, err
		}
		resObj.RawBody = rawBody
		res.Body = ioutil.NopCloser(bytes.NewReader(rawBody))
		if utf8.Valid(rawBody) && !c.Middleware.RawBodyOnly {
			resObj.Body = string(rawBody)
		}
		object.Response = resObj
	}

	return object, nil
}

Cognitive complexity: 45, Cyclomatic complexity: 22

Uses: bytes.NewReader, coprocess.Header, coprocess.HookType_CustomKeyCheck, coprocess.HookType_Pre, coprocess.MiniRequestObject, coprocess.Object, coprocess.ResponseObject, coprocess.ReturnOverrides, ioutil.NopCloser, ioutil.ReadAll, json.Marshal, utf8.Valid.

func (*CoProcessor) Dispatch

func (c *CoProcessor) Dispatch(object *coprocess.Object) (*coprocess.Object, error) {
	dispatcher := loadedDrivers[c.Middleware.MiddlewareDriver]
	if dispatcher == nil {
		err := fmt.Errorf("Couldn't dispatch request, driver '%s' isn't available", c.Middleware.MiddlewareDriver)
		return nil, err
	}
	newObject, err := dispatcher.Dispatch(object)
	if err != nil {
		return nil, err
	}
	return newObject, nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: fmt.Errorf.

func (*CoProcessor) ObjectPostProcess

ObjectPostProcess does CoProcessObject post-processing (adding/removing headers or params, etc.).

func (c *CoProcessor) ObjectPostProcess(object *coprocess.Object, r *http.Request, origURL string, origMethod string) (err error) {
	r.ContentLength = int64(len(object.Request.RawBody))
	r.Body = ioutil.NopCloser(bytes.NewReader(object.Request.RawBody))
	nopCloseRequestBody(r)

	logger := c.Middleware.Logger()

	for _, dh := range object.Request.DeleteHeaders {
		r.Header.Del(dh)
	}
	ignoreCanonical := c.Middleware.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
	for h, v := range object.Request.SetHeaders {
		setCustomHeader(r.Header, h, v, ignoreCanonical)
	}

	updatedValues := r.URL.Query()
	for _, k := range object.Request.DeleteParams {
		updatedValues.Del(k)
	}

	for p, v := range object.Request.AddParams {
		updatedValues.Set(p, v)
	}

	parsedURL, err := url.ParseRequestURI(object.Request.Url)
	if err != nil {
		logger.Error(err)
		return
	}

	rewriteURL := ctxGetURLRewriteTarget(r)
	if rewriteURL != nil {
		ctxSetURLRewriteTarget(r, parsedURL)
		r.URL, err = url.ParseRequestURI(origURL)
		if err != nil {
			logger.Error(err)
			return
		}
	} else {
		r.URL = parsedURL
	}

	transformMethod := ctxGetTransformRequestMethod(r)
	if transformMethod != "" {
		ctxSetTransformRequestMethod(r, object.Request.Method)
		r.Method = origMethod
	} else {
		r.Method = object.Request.Method
	}

	if !reflect.DeepEqual(r.URL.Query(), updatedValues) {
		r.URL.RawQuery = updatedValues.Encode()
	}

	return
}

Cognitive complexity: 26, Cyclomatic complexity: 10

Uses: bytes.NewReader, ioutil.NopCloser, reflect.DeepEqual, url.ParseRequestURI.

func (*CustomMiddlewareResponseHook) HandleError

func (h *CustomMiddlewareResponseHook) HandleError(rw http.ResponseWriter, req *http.Request) {
	handler := ErrorHandler{h.mw.BaseMiddleware.Copy()}
	handler.HandleError(rw, req, "Middleware error", http.StatusInternalServerError, true)
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: http.StatusInternalServerError.

func (*CustomMiddlewareResponseHook) HandleResponse

func (h *CustomMiddlewareResponseHook) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error {
	log.WithFields(logrus.Fields{
		"prefix": "coprocess",
	}).Debugf("Response hook '%s' is called", h.mw.Name())
	coProcessor := CoProcessor{
		Middleware: h.mw,
	}

	object, err := coProcessor.BuildObject(req, res, h.mw.Spec)
	if err != nil {
		log.WithError(err).Debug("Couldn't build request object")
		return errors.New("Middleware error")
	}
	object.Session = ProtoSessionState(ses)

	retObject, err := coProcessor.Dispatch(object)
	if err != nil {
		log.WithError(err).Debug("Couldn't dispatch request object")
		return errors.New("Middleware error")
	}

	if retObject.Response == nil {
		log.WithError(err).Debug("No response object returned by response hook")
		return errors.New("Middleware error")
	}

	// Clear all response headers before populating from coprocess response object:
	for k := range res.Header {
		delete(res.Header, k)
	}

	// check if we have changes in headers
	if !areMapsEqual(object.Response.Headers, retObject.Response.Headers) {
		// as we have changes we need to synchronize them
		retObject.Response.MultivalueHeaders = syncHeadersAndMultiValueHeaders(retObject.Response.Headers, retObject.Response.MultivalueHeaders)
	}

	// Set headers:
	ignoreCanonical := h.mw.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
	for _, v := range retObject.Response.MultivalueHeaders {
		setCustomHeaderMultipleValues(res.Header, v.Key, v.Values, ignoreCanonical)
	}

	// Set response body:
	bodyBuf := bytes.NewBuffer(retObject.Response.RawBody)
	res.Body = ioutil.NopCloser(bodyBuf)

	//set response body length with the size of response body returned from the hook
	//so that it is updated accordingly in the response object
	responseBodyLen := len(retObject.Response.RawBody)
	res.ContentLength = int64(responseBodyLen)
	res.Header.Set("Content-Length", fmt.Sprintf("%d", responseBodyLen))

	res.StatusCode = int(retObject.Response.StatusCode)
	return nil
}

Cognitive complexity: 16, Cyclomatic complexity: 7

Uses: bytes.NewBuffer, errors.New, fmt.Sprintf, ioutil.NopCloser, logrus.Fields.

func (*CustomMiddlewareResponseHook) Init

func (h *CustomMiddlewareResponseHook) Init(mwDef interface{}, spec *APISpec) error {
	mwDefinition := mwDef.(apidef.MiddlewareDefinition)

	h.mw = &CoProcessMiddleware{
		BaseMiddleware: &BaseMiddleware{
			Spec:	spec,
			Gw:	h.Gw,
		},
		HookName:		mwDefinition.Name,
		HookType:		coprocess.HookType_Response,
		RawBodyOnly:		mwDefinition.RawBodyOnly,
		MiddlewareDriver:	spec.CustomMiddleware.Driver,
	}
	return nil
}

Cognitive complexity: 3, Cyclomatic complexity: 1

Uses: apidef.MiddlewareDefinition, coprocess.HookType_Response.

func (*CustomMiddlewareResponseHook) Name

func (h *CustomMiddlewareResponseHook) Name() string {
	return "CustomMiddlewareResponseHook"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*DBAccessDefinition) ToRegularAD

func (d *DBAccessDefinition) ToRegularAD() user.AccessDefinition {
	ad := user.AccessDefinition{
		APIName:		d.APIName,
		APIID:			d.APIID,
		Versions:		d.Versions,
		AllowedURLs:		d.AllowedURLs,
		RestrictedTypes:	d.RestrictedTypes,
		AllowedTypes:		d.AllowedTypes,
		DisableIntrospection:	d.DisableIntrospection,
		FieldAccessRights:	d.FieldAccessRights,
		Endpoints:		d.Endpoints,
	}

	if d.Limit != nil {
		ad.Limit = *d.Limit
	}
	return ad
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: user.AccessDefinition.

func (*DBPolicy) ToRegularPolicy

func (d *DBPolicy) ToRegularPolicy() user.Policy {
	policy := d.Policy
	policy.AccessRights = make(map[string]user.AccessDefinition)

	for k, v := range d.AccessRights {
		policy.AccessRights[k] = v.ToRegularAD()
	}
	return policy
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: user.AccessDefinition.

func (*DefaultHealthChecker) ApiHealthValues

func (h *DefaultHealthChecker) ApiHealthValues() (HealthCheckValues, error) {
	values := HealthCheckValues{}

	// Get the counted / average values
	values.ThrottledRequestsPS = h.getAvgCount(Throttle)
	values.QuotaViolationsPS = h.getAvgCount(QuotaViolation)
	values.KeyFailuresPS = h.getAvgCount(KeyFailure)
	values.AvgRequestsPS = h.getAvgCount(RequestLog)

	// Get the micro latency graph, an average upstream latency
	searchStr := h.APIID + "." + string(RequestLog)
	log.Debug("Searching KV for: ", searchStr)
	_, vals := h.storage.SetRollingWindow(searchStr, h.Gw.GetConfig().HealthCheck.HealthCheckValueTimeout, "-1", false)
	log.Debug("Found: ", vals)
	if len(vals) == 0 {
		return values, nil
	}
	var runningTotal int
	for _, v := range vals {
		s := v.(string)
		log.Debug("V is: ", s)
		splitValues := strings.Split(s, ".")
		if len(splitValues) > 1 {
			vInt, err := strconv.Atoi(splitValues[1])
			if err != nil {
				log.Error("Couldn't convert tracked latency value to Int, vl is: ", err)
			} else {
				runningTotal += vInt
			}
		}

	}
	values.AvgUpstreamLatency = roundValue(float64(runningTotal / len(vals)))
	return values, nil
}

Cognitive complexity: 12, Cyclomatic complexity: 5

Uses: strconv.Atoi, strings.Split.

func (*DefaultHealthChecker) CreateKeyName

func (h *DefaultHealthChecker) CreateKeyName(subKey HealthPrefix) string {
	// Key should be API-ID.SubKey.123456789
	return h.APIID + "." + string(subKey)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*DefaultHealthChecker) Init

func (h *DefaultHealthChecker) Init(storeType storage.Handler) {
	if !h.Gw.GetConfig().HealthCheck.EnableHealthChecks {
		return
	}

	log.Info("Initializing HealthChecker")
	h.storage = storeType
	h.storage.Connect()
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*DefaultHealthChecker) StoreCounterVal

func (h *DefaultHealthChecker) StoreCounterVal(counterType HealthPrefix, value string) {
	searchStr := h.CreateKeyName(counterType)
	log.Debug("Adding Healthcheck to: ", searchStr)
	log.Debug("Val is: ", value)
	//go h.storage.SetKey(searchStr, value, config.Global.HealthCheck.HealthCheckValueTimeout)
	if value != "-1" {
		// need to ensure uniqueness
		now_string := strconv.Itoa(int(time.Now().UnixNano()))
		value = now_string + "." + value
		log.Debug("Set value to: ", value)
	}
	go h.storage.SetRollingWindow(searchStr, h.Gw.GetConfig().HealthCheck.HealthCheckValueTimeout, value, false)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: strconv.Itoa, time.Now.

func (*DefaultSessionManager) Init

func (b *DefaultSessionManager) Init(store storage.Handler) {
	b.store = store
	b.store.Connect()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*DefaultSessionManager) KeyExpired

KeyExpired checks if a key has expired, if the value of user.SessionState.Expires is 0, it will be ignored

func (b *DefaultSessionManager) KeyExpired(newSession *user.SessionState) bool {
	if newSession.Expires >= 1 {
		return time.Now().After(time.Unix(newSession.Expires, 0))
	}
	return false
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: time.Now, time.Unix.

func (*DefaultSessionManager) RemoveSession

RemoveSession removes session from storage

func (b *DefaultSessionManager) RemoveSession(orgID string, keyName string, hashed bool) bool {
	defer b.clearCacheForKey(keyName, hashed)

	if hashed {
		return b.store.DeleteRawKey(b.store.GetKeyPrefix() + keyName)
	} else {
		// support both old and new key hashing
		res1 := b.store.DeleteKey(keyName)
		res2 := b.store.DeleteKey(b.Gw.generateToken(orgID, keyName))
		return res1 || res2
	}
}

Cognitive complexity: 4, Cyclomatic complexity: 3

func (*DefaultSessionManager) ResetQuota

func (b *DefaultSessionManager) ResetQuota(keyName string, session *user.SessionState, isHashed bool) {
	origKeyName := keyName

	if !isHashed {
		keyName = storage.HashKey(keyName, b.Gw.GetConfig().HashKeys)
	}

	rawKey := QuotaKeyPrefix + keyName
	log.WithFields(logrus.Fields{
		"prefix":	"auth-mgr",
		"inbound-key":	b.Gw.obfuscateKey(origKeyName),
		"key":		b.ResetQuotaObfuscateKey(keyName),
	}).Info("Reset quota for key.")

	rateLimiterSentinelKey := RateLimitKeyPrefix + keyName + ".BLOCKED"

	// Clear the rate limiter and
	// Fix the raw key
	defaultKeys := []string{rateLimiterSentinelKey, rawKey}
	keys := rawKeysWithAllowanceScope(defaultKeys, keyName, session)
	b.store.DeleteRawKeys(keys)
}

Cognitive complexity: 4, Cyclomatic complexity: 2

Uses: logrus.Fields, storage.HashKey.

func (*DefaultSessionManager) ResetQuotaObfuscateKey

func (b *DefaultSessionManager) ResetQuotaObfuscateKey(keyName string) string {
	if !b.Gw.GetConfig().HashKeys && !b.Gw.GetConfig().EnableKeyLogging {
		return b.Gw.obfuscateKey(keyName)
	}
	return keyName
}

Cognitive complexity: 2, Cyclomatic complexity: 3

func (*DefaultSessionManager) SessionDetail

SessionDetail returns the session detail using the storage engine (either in memory or Redis)

func (b *DefaultSessionManager) SessionDetail(orgID string, keyName string, hashed bool) (user.SessionState, bool) {
	var jsonKeyVal string
	var err error
	keyId := keyName

	// get session by key
	if hashed {
		jsonKeyVal, err = b.store.GetRawKey(b.store.GetKeyPrefix() + keyName)
	} else {
		if storage.TokenOrg(keyName) != orgID {
			// try to get legacy and new format key at once
			toSearchList := []string{}
			if !b.Gw.GetConfig().DisableKeyActionsByUsername {
				toSearchList = append(toSearchList, b.Gw.generateToken(orgID, keyName))
			}

			toSearchList = append(toSearchList, keyName)
			for _, fallback := range b.Gw.GetConfig().HashKeyFunctionFallback {
				if !b.Gw.GetConfig().DisableKeyActionsByUsername {
					toSearchList = append(toSearchList, b.Gw.generateToken(orgID, keyName, fallback))
				}
			}

			var jsonKeyValList []string

			jsonKeyValList, err = b.store.GetMultiKey(toSearchList)
			// pick the 1st non empty from the returned list
			for idx, val := range jsonKeyValList {
				if val != "" {
					jsonKeyVal = val
					keyId = toSearchList[idx]
					break
				}
			}
		} else {
			// key is not an imported one
			jsonKeyVal, err = b.store.GetKey(keyName)
		}
	}

	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix":	"auth-mgr",
			"inbound-key":	b.Gw.obfuscateKey(keyName),
			"err":		err,
		}).Debug("Could not get session detail, key not found")
		return user.SessionState{}, false
	}
	session := &user.SessionState{}
	if err := json.Unmarshal([]byte(jsonKeyVal), &session); err != nil {
		log.Error("Couldn't unmarshal session object (may be cache miss): ", err)
		return user.SessionState{}, false
	}
	session.KeyID = keyId
	return session.Clone(), true
}

Cognitive complexity: 29, Cyclomatic complexity: 10

Uses: json.Unmarshal, logrus.Fields, storage.TokenOrg, user.SessionState.

func (*DefaultSessionManager) Sessions

Sessions returns all sessions in the key store that match a filter key (a prefix)

func (b *DefaultSessionManager) Sessions(filter string) []string {
	return b.store.GetKeys(filter)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*DefaultSessionManager) Stop

func (b *DefaultSessionManager) Stop()	{}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*DefaultSessionManager) Store

func (b *DefaultSessionManager) Store() storage.Handler {
	return b.store
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*DefaultSessionManager) UpdateSession

UpdateSession updates the session state in the storage engine

func (b *DefaultSessionManager) UpdateSession(keyName string, session *user.SessionState,
	resetTTLTo int64, hashed bool) error {
	defer b.clearCacheForKey(keyName, hashed)

	v, err := json.Marshal(session)
	if err != nil {
		log.Error("Error marshalling session for sync update")
		return err
	}

	// sync update
	if hashed {
		keyName = b.store.GetKeyPrefix() + keyName
		err = b.store.SetRawKey(keyName, string(v), resetTTLTo)
	} else {
		err = b.store.SetKey(keyName, string(v), resetTTLTo)
	}

	return err
}

Cognitive complexity: 6, Cyclomatic complexity: 3

Uses: json.Marshal.

func (*DummyProxyHandler) ServeHTTP

func (d *DummyProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if newURL := ctxGetURLRewriteTarget(r); newURL != nil {
		r.URL = newURL
		ctxSetURLRewriteTarget(r, nil)
	}
	if newMethod := ctxGetTransformRequestMethod(r); newMethod != "" {
		r.Method = newMethod
		ctxSetTransformRequestMethod(r, "")
	}
	if found, err := isLoop(r); found {
		if err != nil {
			handler := ErrorHandler{d.SH.Base()}
			handler.HandleError(w, r, err.Error(), http.StatusInternalServerError, true)
			return
		}

		r.URL.Scheme = "http"
		if methodOverride := r.URL.Query().Get("method"); methodOverride != "" {
			r.Method = methodOverride
		}

		var handler http.Handler
		if r.URL.Hostname() == "self" {
			httpctx.SetSelfLooping(r, true)
			if h, found := d.Gw.apisHandlesByID.Load(d.SH.Spec.APIID); found {
				if chain, ok := h.(*ChainObject); ok {
					handler = chain.ThisHandler
				} else {
					log.WithFields(logrus.Fields{"api_id": d.SH.Spec.APIID}).Debug("failed to cast stored api handles to *ChainObject")
				}
			}
		} else {
			ctxSetVersionInfo(r, nil)

			if targetAPI := d.Gw.fuzzyFindAPI(r.URL.Hostname()); targetAPI != nil {
				if h, found := d.Gw.apisHandlesByID.Load(targetAPI.APIID); found {
					if chain, ok := h.(*ChainObject); ok {
						handler = chain.ThisHandler
					} else {
						log.WithFields(logrus.Fields{"api_id": d.SH.Spec.APIID}).Debug("failed to cast stored api handles to *ChainObject")
					}
				}
			} else {
				handler := ErrorHandler{d.SH.Base()}
				handler.HandleError(w, r, "Can't detect loop target", http.StatusInternalServerError, true)
				return
			}
		}

		// No need to handle errors, in all error cases limit will be set to 0
		loopLevelLimit, _ := strconv.Atoi(r.URL.Query().Get("loop_limit"))
		ctxSetCheckLoopLimits(r, r.URL.Query().Get("check_limits") == "true")

		if origURL := ctxGetOrigRequestURL(r); origURL != nil {
			r.URL.Host = origURL.Host
			r.URL.RawQuery = origURL.RawQuery
			ctxSetOrigRequestURL(r, nil)
		}

		ctxIncLoopLevel(r, loopLevelLimit)
		handler.ServeHTTP(w, r)
		return
	}

	if d.SH.Spec.target.Scheme == "tyk" {
		handler, _, found := d.Gw.findInternalHttpHandlerByNameOrID(d.SH.Spec.target.Host)
		if !found {
			handler := ErrorHandler{d.SH.Base()}
			handler.HandleError(w, r, "Couldn't detect target", http.StatusInternalServerError, true)
			return
		}

		d.SH.Spec.SanitizeProxyPaths(r)
		ctxSetVersionInfo(r, nil)
		handler.ServeHTTP(w, r)
		return
	}

	d.SH.ServeHTTP(w, r)
}

Cognitive complexity: 41, Cyclomatic complexity: 15

Uses: http.Handler, http.StatusInternalServerError, httpctx.SetSelfLooping, logrus.Fields, strconv.Atoi.

func (*DynamicMiddleware) Name

func (d *DynamicMiddleware) Name() string {
	return "DynamicMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*DynamicMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (d *DynamicMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	t1 := time.Now().UnixNano()
	logger := d.Logger()

	// Create the proxy object
	originalBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		logger.WithError(err).Error("Failed to read request body")
		return nil, http.StatusOK
	}
	defer r.Body.Close()

	headers := r.Header
	host := r.Host
	if host == "" && r.URL != nil {
		host = r.URL.Host
	}
	if host != "" {
		headers = make(http.Header)
		for k, v := range r.Header {
			headers[k] = v
		}
		headers.Set("Host", host)
	}
	scheme := "http"
	if r.TLS != nil {
		scheme = "https"
	}

	requestData := MiniRequestObject{
		Headers:	headers,
		SetHeaders:	map[string]string{},
		DeleteHeaders:	[]string{},
		Body:		originalBody,
		URL:		r.URL.String(),
		Params:		r.URL.Query(),
		AddParams:	map[string]string{},
		ExtendedParams:	map[string][]string{},
		DeleteParams:	[]string{},
		Method:		r.Method,
		RequestURI:	r.RequestURI,
		Scheme:		scheme,
	}

	requestAsJson, err := json.Marshal(requestData)
	if err != nil {
		logger.WithError(err).Error("Failed to encode request object for dynamic middleware")
		return nil, http.StatusOK
	}

	specAsJson := specToJson(d.Spec)

	session := &user.SessionState{}

	// Encode the session object (if not a pre-process)
	if !d.Pre && d.UseSession {
		session = ctxGetSession(r)
	}

	sessionAsJson, err := json.Marshal(session)
	if err != nil {
		logger.WithError(err).Error("Failed to encode session for VM")
		return nil, http.StatusOK
	}

	// Run the middleware
	middlewareClassname := d.MiddlewareClassName
	if d.Spec.JSVM.VM == nil {
		logger.WithError(err).Error("JSVM isn't enabled, check your gateway settings")
		return errors.New("Middleware error"), 500
	}
	vm := d.Spec.JSVM.VM.Copy()
	vm.Interrupt = make(chan func(), 1)
	logger.Debug("Running: ", middlewareClassname)
	// buffered, leaving no chance of a goroutine leak since the
	// spawned goroutine will send 0 or 1 values.
	ret := make(chan otto.Value, 1)
	errRet := make(chan error, 1)
	go func() {
		defer func() {
			// the VM executes the panic func that gets it
			// to stop, so we must recover here to not crash
			// the whole Go program.
			recover()
		}()
		returnRaw, err := vm.Run(middlewareClassname + `.DoProcessRequest(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`)
		ret <- returnRaw
		errRet <- err
	}()
	var returnRaw otto.Value
	t := time.NewTimer(d.Spec.JSVM.Timeout)
	select {
	case returnRaw = <-ret:
		if err := <-errRet; err != nil {
			logger.WithError(err).Error("Failed to run JS middleware")
			return errors.New(http.StatusText(http.StatusInternalServerError)), http.StatusInternalServerError
		}
		t.Stop()
	case <-t.C:
		t.Stop()
		logger.Error("JS middleware timed out after ", d.Spec.JSVM.Timeout)
		vm.Interrupt <- func() {
			// only way to stop the VM is to send it a func
			// that panics.
			panic("stop")
		}
		return errors.New(http.StatusText(http.StatusInternalServerError)), http.StatusInternalServerError
	}
	returnDataStr, _ := returnRaw.ToString()

	// Decode the return object
	newRequestData := VMReturnObject{}
	if err := json.Unmarshal([]byte(returnDataStr), &newRequestData); err != nil {
		logger.WithError(err).Error("Failed to decode middleware request data on return from VM. Returned data: ", returnDataStr)
		return errors.New(http.StatusText(http.StatusInternalServerError)), http.StatusInternalServerError
	}

	// Reconstruct the request parts
	if newRequestData.Request.IgnoreBody {
		r.ContentLength = int64(len(originalBody))
		r.Body = ioutil.NopCloser(bytes.NewReader(originalBody))
	} else {
		r.ContentLength = int64(len(newRequestData.Request.Body))
		r.Body = ioutil.NopCloser(bytes.NewReader(newRequestData.Request.Body))
	}

	// make sure request's body can be re-read again
	nopCloseRequestBody(r)

	r.URL, err = url.Parse(newRequestData.Request.URL)
	if err != nil {
		return nil, http.StatusOK
	}

	ignoreCanonical := d.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
	// Delete and set headers
	for _, dh := range newRequestData.Request.DeleteHeaders {
		r.Header.Del(dh)
		if ignoreCanonical {
			// Make sure we delete the header in case the header key was not canonical.
			delete(r.Header, dh)
		}
	}
	for h, v := range newRequestData.Request.SetHeaders {
		setCustomHeader(r.Header, h, v, ignoreCanonical)
	}

	// Delete and set request parameters
	newRequestData.Request.ReconstructParams(r)

	// Save the session data (if modified)
	if !d.Pre && d.UseSession {
		newMeta := mapStrsToIfaces(newRequestData.SessionMeta)
		if session != nil && !reflect.DeepEqual(session.MetaData, newMeta) {
			session.MetaData = newMeta
			session.Touch()
		}
	}

	logger.Debug("JSVM middleware execution took: (ns) ", time.Now().UnixNano()-t1)

	if newRequestData.Request.ReturnOverrides.ResponseError != "" {
		newRequestData.Request.ReturnOverrides.ResponseBody = newRequestData.Request.ReturnOverrides.ResponseError
	}

	if newRequestData.Request.ReturnOverrides.ResponseCode >= http.StatusBadRequest && !newRequestData.Request.ReturnOverrides.OverrideError {

		for header, value := range newRequestData.Request.ReturnOverrides.ResponseHeaders {
			w.Header().Set(header, value)
		}

		return errors.New(newRequestData.Request.ReturnOverrides.ResponseBody), newRequestData.Request.ReturnOverrides.ResponseCode
	}

	if newRequestData.Request.ReturnOverrides.ResponseCode != 0 {
		responseObject := VMResponseObject{
			Response: ResponseObject{
				Body:		newRequestData.Request.ReturnOverrides.ResponseBody,
				Code:		newRequestData.Request.ReturnOverrides.ResponseCode,
				Headers:	newRequestData.Request.ReturnOverrides.ResponseHeaders,
			},
		}

		d.Gw.forceResponse(w, r, &responseObject, d.Spec, session, d.Pre, logger)
		return nil, mwStatusRespond
	}

	if d.Auth {
		newRequestData.Session.KeyID = newRequestData.AuthValue

		switch d.Spec.BaseIdentityProvidedBy {
		case apidef.CustomAuth, apidef.UnsetAuth:
			ctxSetSession(r, &newRequestData.Session, true, d.Gw.GetConfig().HashKeys)
		}
	}

	return nil, http.StatusOK
}

Cognitive complexity: 72, Cyclomatic complexity: 33

Uses: apidef.CustomAuth, apidef.UnsetAuth, bytes.NewReader, errors.New, http.Header, http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, http.StatusText, ioutil.NopCloser, ioutil.ReadAll, json.Marshal, json.Unmarshal, otto.Value, reflect.DeepEqual, time.NewTimer, time.Now, url.Parse, user.SessionState.

func (*ErrorHandler) HandleError

HandleError is the actual error handler and will store the error details in analytics if analytics processing is enabled.

func (e *ErrorHandler) HandleError(w http.ResponseWriter, r *http.Request, errMsg string, errCode int, writeResponse bool) {
	defer e.Base().UpdateRequestSession(r)
	response := &http.Response{}

	if writeResponse {
		var templateExtension string
		contentType := r.Header.Get(header.ContentType)
		contentType = strings.Split(contentType, ";")[0]

		switch contentType {
		case header.ApplicationXML:
			templateExtension = "xml"
			contentType = header.ApplicationXML
		case header.TextXML:
			templateExtension = "xml"
			contentType = header.TextXML
		default:
			templateExtension = "json"
			contentType = header.ApplicationJSON
		}

		w.Header().Set(header.ContentType, contentType)
		response.Header = http.Header{}
		response.Header.Set(header.ContentType, contentType)
		templateName := "error_" + strconv.Itoa(errCode) + "." + templateExtension

		// Try to use an error template that matches the HTTP error code and the content type: 500.json, 400.xml, etc.
		tmpl := e.Gw.templates.Lookup(templateName)

		// Fallback to a generic error template, but match the content type: error.json, error.xml, etc.
		if tmpl == nil {
			templateName = defaultTemplateName + "." + templateExtension
			tmpl = e.Gw.templates.Lookup(templateName)
		}

		// If no template is available for this content type, fallback to "error.json".
		if tmpl == nil {
			templateName = defaultTemplateName + "." + defaultTemplateFormat
			tmpl = e.Gw.templates.Lookup(templateName)
			w.Header().Set(header.ContentType, defaultContentType)
			response.Header.Set(header.ContentType, defaultContentType)

		}

		//If the config option is not set or is false, add the header
		if !e.Spec.GlobalConfig.HideGeneratorHeader {
			w.Header().Add(header.XGenerator, "tyk.io")
			response.Header.Add(header.XGenerator, "tyk.io")
		}

		// Close connections
		if e.Spec.GlobalConfig.CloseConnections {
			w.Header().Add(header.Connection, "close")
			response.Header.Add(header.Connection, "close")

		}

		// If error is not customized write error in default way
		if errMsg != errCustomBodyResponse.Error() {
			w.WriteHeader(errCode)
			response.StatusCode = errCode
			var tmplExecutor TemplateExecutor
			tmplExecutor = tmpl

			apiError := APIError{htmltemplate.HTML(htmltemplate.JSEscapeString(errMsg))}

			if contentType == header.ApplicationXML || contentType == header.TextXML {
				apiError.Message = htmltemplate.HTML(errMsg)

				//we look up in the last defined templateName to obtain the template.
				rawTmpl := e.Gw.templatesRaw.Lookup(templateName)
				tmplExecutor = rawTmpl
			}

			var log bytes.Buffer

			rsp := io.MultiWriter(w, &log)
			tmplExecutor.Execute(rsp, &apiError)
			response.Body = ioutil.NopCloser(&log)
		}
	}

	if e.Spec.DoNotTrack || ctxGetDoNotTrack(r) {
		return
	}

	// Track the key ID if it exists
	token := ctxGetAuthToken(r)
	var alias string

	ip := request.RealIP(r)

	if e.Spec.GlobalConfig.StoreAnalytics(ip) {

		t := time.Now()

		addVersionHeader(w, r, e.Spec.GlobalConfig)

		version := e.Spec.getVersionFromRequest(r)

		if version == "" {
			version = "Non Versioned"
		}

		if e.Spec.Proxy.StripListenPath {
			r.URL.Path = e.Spec.StripListenPath(r.URL.Path)
		}

		oauthClientID := ""
		session := ctxGetSession(r)
		tags := make([]string, 0, estimateTagsCapacity(session, e.Spec))

		if session != nil {
			oauthClientID = session.OauthClientID
			alias = session.Alias
			tags = append(tags, getSessionTags(session)...)
		}

		if len(e.Spec.TagHeaders) > 0 {
			tags = tagHeaders(r, e.Spec.TagHeaders, tags)
		}

		if len(e.Spec.Tags) > 0 {
			tags = append(tags, e.Spec.Tags...)
		}
		trackEP := false
		trackedPath := r.URL.Path

		if p := ctxGetTrackedPath(r); p != "" {
			trackEP = true
			trackedPath = p
		}

		host := r.URL.Host

		if host == "" && e.Spec.target != nil {
			host = e.Spec.target.Host
		}

		record := analytics.AnalyticsRecord{
			Method:		r.Method,
			Host:		host,
			Path:		trackedPath,
			RawPath:	r.URL.Path,
			ContentLength:	r.ContentLength,
			UserAgent:	r.Header.Get(header.UserAgent),
			Day:		t.Day(),
			Month:		t.Month(),
			Year:		t.Year(),
			Hour:		t.Hour(),
			ResponseCode:	errCode,
			APIKey:		token,
			TimeStamp:	t,
			APIVersion:	version,
			APIName:	e.Spec.Name,
			APIID:		e.Spec.APIID,
			OrgID:		e.Spec.OrgID,
			OauthID:	oauthClientID,
			RequestTime:	0,
			Latency:	analytics.Latency{},
			IPAddress:	ip,
			Geo:		analytics.GeoData{},
			Network:	analytics.NetworkStats{},
			Tags:		tags,
			Alias:		alias,
			TrackPath:	trackEP,
			ExpireAt:	t,
		}
		recordGraphDetails(&record, r, response, e.Spec)

		rawRequest := ""
		rawResponse := ""
		if recordDetail(r, e.Spec) {

			// Get the wire format representation

			var wireFormatReq bytes.Buffer
			r.Write(&wireFormatReq)
			rawRequest = base64.StdEncoding.EncodeToString(wireFormatReq.Bytes())

			var wireFormatRes bytes.Buffer
			response.Write(&wireFormatRes)
			rawResponse = base64.StdEncoding.EncodeToString(wireFormatRes.Bytes())

		}

		record.RawRequest = rawRequest
		record.RawResponse = rawResponse

		if e.Spec.GlobalConfig.AnalyticsConfig.EnableGeoIP {
			record.GetGeo(ip, e.Gw.Analytics.GeoIPDB)
		}
		if e.Spec.GraphQL.Enabled && e.Spec.GraphQL.ExecutionMode != apidef.GraphQLExecutionModeSubgraph {
			record.Tags = append(record.Tags, "tyk-graph-analytics")
			record.ApiSchema = base64.StdEncoding.EncodeToString([]byte(e.Spec.GraphQL.Schema))
		}

		expiresAfter := e.Spec.ExpireAnalyticsAfter

		if e.Spec.GlobalConfig.EnforceOrgDataAge {
			orgExpireDataTime := e.OrgSessionExpiry(e.Spec.OrgID)

			if orgExpireDataTime > 0 {
				expiresAfter = orgExpireDataTime
			}
		}

		record.SetExpiry(expiresAfter)

		if e.Spec.GlobalConfig.AnalyticsConfig.NormaliseUrls.Enabled {
			NormalisePath(&record, &e.Spec.GlobalConfig)
		}

		if e.Spec.AnalyticsPlugin.Enabled {
			_ = e.Spec.AnalyticsPluginConfig.processRecord(&record)
		}

		err := e.Gw.Analytics.RecordHit(&record)

		if err != nil {
			log.WithError(err).Error("could not store analytic record")
		}
	}

	e.RecordAccessLog(r, response, analytics.Latency{})

	// Report in health check
	reportHealthValue(e.Spec, BlockedRequestLog, "-1")
}

Cognitive complexity: 60, Cyclomatic complexity: 32

Uses: analytics.AnalyticsRecord, analytics.GeoData, analytics.Latency, analytics.NetworkStats, apidef.GraphQLExecutionModeSubgraph, base64.StdEncoding, bytes.Buffer, header.ApplicationJSON, header.ApplicationXML, header.Connection, header.ContentType, header.TextXML, header.UserAgent, header.XGenerator, htmltemplate.HTML, htmltemplate.JSEscapeString, http.Header, http.Response, io.MultiWriter, ioutil.NopCloser, request.RealIP, strconv.Itoa, strings.Split, time.Now.

func (*EventCurcuitBreakerMeta) LogMessage

func (e *EventCurcuitBreakerMeta) LogMessage(prefix string) string {
	return fmt.Sprintf("%s:%s:%s: [STATUS] %s", prefix, e.APIID, e.Path, fmt.Sprint(e.CircuitEvent))
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: fmt.Sprint, fmt.Sprintf.

func (*EventKeyFailureMeta) LogMessage

func (e *EventKeyFailureMeta) LogMessage(prefix string) string {
	return fmt.Sprintf("%s:%s:%s:%s", prefix, e.Key, e.Origin, e.Path)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: fmt.Sprintf.

func (*ExternalOAuthMiddleware) EnabledForSpec

func (k *ExternalOAuthMiddleware) EnabledForSpec() bool {
	if k.Spec.ExternalOAuth.Enabled {
		log.Warn("Support for external OAuth Middleware will be deprecated starting from 5.7.0. To avoid any disruptions, we recommend that you use JSON Web Token (JWT) instead, as explained in https://tyk.io/docs/basic-config-and-security/security/authentication-authorization/ext-oauth-middleware/")
	}

	return k.Spec.ExternalOAuth.Enabled
}

Cognitive complexity: 3, Cyclomatic complexity: 3

func (*ExternalOAuthMiddleware) Name

func (k *ExternalOAuthMiddleware) Name() string {
	return "ExternalOAuth"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ExternalOAuthMiddleware) ProcessRequest

func (k *ExternalOAuthMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	token, _ := k.getAuthToken(k.getAuthType(), r)
	if token == "" {
		return errors.New("authorization field missing"), http.StatusBadRequest
	}

	token = stripBearer(token)

	var (
		valid		bool
		err		error
		identifier	string
	)

	if len(k.Spec.ExternalOAuth.Providers) == 0 {
		return errors.New("there should be at least one provider configured"), http.StatusNotFound
	}

	// Just the first one will be used, later there can be multiple providers supported
	provider := k.Spec.ExternalOAuth.Providers[0]

	if provider.JWT.Enabled {
		valid, identifier, err = k.jwt(token)
	} else if provider.Introspection.Enabled {
		valid, identifier, err = k.introspection(token)
	} else {
		return errors.New("access token validation method is not specified"), http.StatusInternalServerError
	}

	if err != nil {
		switch {
		case errors.Is(err, jwt.ErrSignatureInvalid), errors.Is(err, jwt.ErrTokenMalformed), errors.Is(err, jwt.ErrTokenNotValidYet),
			errors.Is(err, jwt.ErrTokenUsedBeforeIssued), errors.Is(err, jwt.ErrTokenExpired):
			return err, http.StatusUnauthorized
		}

		return ErrTokenValidationFailed, http.StatusInternalServerError
	}

	if !valid {
		return errors.New("access token is not valid"), http.StatusUnauthorized
	}

	sessionID := k.generateSessionID(identifier)

	k.Logger().Debug("External OAuth Temporary session ID is: ", sessionID)

	// CheckSessionAndIdentityForValidKey returns a session with keyID populated
	var virtualSession user.SessionState
	virtualSession, exists := k.CheckSessionAndIdentityForValidKey(sessionID, r)
	if !exists {
		virtualSession = k.generateVirtualSessionFor(r, sessionID)
	}

	ctxSetSession(r, &virtualSession, false, k.Gw.GetConfig().HashKeys)

	// Request is valid, carry on
	return nil, http.StatusOK
}

Cognitive complexity: 22, Cyclomatic complexity: 11

Uses: errors.Is, errors.New, http.StatusBadRequest, http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, http.StatusUnauthorized, user.SessionState.

func (*FileBundleGetter) Get

Get mocks an HTTP(S) GET request.

func (g *FileBundleGetter) Get() ([]byte, error) {
	return os.ReadFile(strings.TrimPrefix(g.URL, "file://"))
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: os.ReadFile, strings.TrimPrefix.

func (*GRPCDispatcher) Dispatch

Dispatch takes a CoProcessMessage and sends it to the CP.

func (d *GRPCDispatcher) Dispatch(object *coprocess.Object) (*coprocess.Object, error) {
	return grpcClient.Dispatch(context.Background(), object)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: context.Background.

func (*GRPCDispatcher) DispatchEvent

DispatchEvent dispatches a Tyk event.

func (d *GRPCDispatcher) DispatchEvent(eventJSON []byte) {
	eventObject := &coprocess.Event{
		Payload: string(eventJSON),
	}

	_, err := grpcClient.DispatchEvent(context.Background(), eventObject)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error(err)
	}
}

Cognitive complexity: 4, Cyclomatic complexity: 2

Uses: context.Background, coprocess.Event, logrus.Fields.

func (*GRPCDispatcher) HandleMiddlewareCache

HandleMiddlewareCache isn't used by gRPC.

func (d *GRPCDispatcher) HandleMiddlewareCache(b *apidef.BundleManifest, basePath string)	{}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GRPCDispatcher) Reload

Reload triggers a reload affecting CP middlewares and event handlers.

func (d *GRPCDispatcher) Reload()	{}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Gateway) ApplyLifetime

ApplyLifetime calculates the lifetime for the key. It considers the access rights and the bigger lifetime will be used

func (gw *Gateway) ApplyLifetime(sess *user.SessionState, specs ...*APISpec) int64 {
	var lifetime int64

	if len(sess.AccessRights) > 0 {
		specs = gw.GetApiSpecsFromAccessRights(sess)
	}

	for _, spec := range specs {
		if spec != nil {
			sessionLifeTime := sess.Lifetime(spec.GetSessionLifetimeRespectsKeyExpiration(), spec.SessionLifetime, gw.GetConfig().ForceGlobalSessionLifetime, gw.GetConfig().GlobalSessionLifetime)
			// uses the greater lifetime
			if sessionLifeTime > lifetime {
				lifetime = sessionLifeTime
			}
		}
	}

	return lifetime
}

Cognitive complexity: 9, Cyclomatic complexity: 5

func (*Gateway) BuildAndLoadAPI

func (gw *Gateway) BuildAndLoadAPI(apiGens ...func(spec *APISpec)) (specs []*APISpec) {
	return gw.LoadAPI(BuildAPI(apiGens...)...)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Gateway) CoProcessInit

CoProcessInit creates a new CoProcessDispatcher, it will be called when Tyk starts.

func (gw *Gateway) CoProcessInit() {
	if !gw.GetConfig().CoProcessOptions.EnableCoProcess {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Info("Rich plugins are disabled")
		return
	}

	// Load gRPC dispatcher:
	if gw.GetConfig().CoProcessOptions.CoProcessGRPCServer != "" {
		var err error
		loadedDrivers[apidef.GrpcDriver], err = gw.NewGRPCDispatcher()
		if err == nil {
			log.WithFields(logrus.Fields{
				"prefix": "coprocess",
			}).Info("gRPC dispatcher was initialized")
		} else {
			log.WithFields(logrus.Fields{
				"prefix": "coprocess",
			}).WithError(err).Error("Couldn't load gRPC dispatcher")
		}
	}

}

Cognitive complexity: 11, Cyclomatic complexity: 4

Uses: apidef.GrpcDriver, logrus.Fields.

func (*Gateway) CreateDefinitionFromString

func (gw *Gateway) CreateDefinitionFromString(defStr string) *APISpec {
	loader := APIDefinitionLoader{Gw: gw}
	def := loader.ParseDefinition(strings.NewReader(defStr))
	spec, _ := loader.MakeSpec(&model.MergedAPI{APIDefinition: &def}, nil)
	return spec
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: model.MergedAPI, strings.NewReader.

func (*Gateway) DoReload

func (gw *Gateway) DoReload() {
	gw.reloadMu.Lock()
	defer gw.reloadMu.Unlock()

	// Initialize/reset the JSVM
	if gw.GetConfig().EnableJSVM {
		gw.GlobalEventsJSVM.DeInit()
		gw.GlobalEventsJSVM.Init(nil, logrus.NewEntry(log), gw)
	}

	// Load the API Policies
	if _, err := syncResourcesWithReload("policies", gw.GetConfig(), gw.syncPolicies); err != nil {
		mainLog.Error("Error during syncing policies")
		return
	}

	// load the specs
	if count, err := syncResourcesWithReload("apis", gw.GetConfig(), gw.syncAPISpecs); err != nil {
		mainLog.Error("Error during syncing apis")
		return
	} else {
		// skip re-loading only if dashboard service reported 0 APIs
		// and current registry had 0 APIs
		if count == 0 && gw.apisByIDLen() == 0 {
			mainLog.Warning("No API Definitions found, not reloading")
			return
		}
	}

	gw.loadGlobalApps()

	mainLog.Info("API reload complete")
}

Cognitive complexity: 10, Cyclomatic complexity: 6

Uses: logrus.NewEntry.

func (*Gateway) EventHandlerByName

EventHandlerByName is a convenience function to get event handler instances from an API Definition

func (gw *Gateway) EventHandlerByName(handlerConf apidef.EventHandlerTriggerConfig, spec *APISpec) (config.TykEventHandler, error) {

	conf := handlerConf.HandlerMeta
	switch handlerConf.Handler {
	case EH_LogHandler:
		h := &LogMessageEventHandler{Gw: gw}
		err := h.Init(conf)
		return h, err
	case EH_WebHook:
		h := &WebHookHandler{Gw: gw}
		err := h.Init(conf)
		return h, err
	case EH_JSVMHandler:
		// Load the globals and file here
		if spec != nil {
			h := &JSVMEventHandler{Spec: spec, Gw: gw}
			err := h.Init(conf)
			if err == nil {
				gw.GlobalEventsJSVM.LoadJSPaths([]string{conf["path"].(string)}, "")
			}
			return h, err
		}
	case EH_CoProcessHandler:
		if spec != nil {
			dispatcher := loadedDrivers[spec.CustomMiddleware.Driver]
			if dispatcher == nil {
				return nil, errors.New("no plugin driver is available")
			}
			h := &CoProcessEventHandler{}
			h.Spec = spec
			err := h.Init(conf)
			return h, err
		}
	}

	return nil, errors.New("Handler not found")
}

Cognitive complexity: 19, Cyclomatic complexity: 10

Uses: errors.New.

func (*Gateway) FetchBundle

FetchBundle will fetch a given bundle, using the right BundleGetter. The first argument is the bundle name, the base bundle URL will be used as prefix.

func (gw *Gateway) FetchBundle(spec *APISpec) (Bundle, error) {
	bundle := Bundle{Gw: gw}
	var err error

	if !gw.GetConfig().EnableBundleDownloader {
		log.WithFields(logrus.Fields{
			"prefix": "main",
		}).Warning("Bundle downloader is disabled.")
		err = errors.New("Bundle downloader is disabled")
		return bundle, err
	}

	u, err := url.Parse(gw.GetConfig().BundleBaseURL)
	if err != nil {
		return bundle, err
	}

	u.Path = path.Join(u.Path, spec.CustomMiddlewareBundle)

	bundleURL := u.String()

	var getter BundleGetter

	switch u.Scheme {
	case "http":
		getter = &HTTPBundleGetter{
			URL:			bundleURL,
			InsecureSkipVerify:	false,
		}
	case "https":
		getter = &HTTPBundleGetter{
			URL:			bundleURL,
			InsecureSkipVerify:	gw.GetConfig().BundleInsecureSkipVerify,
		}
	case "file":
		getter = &FileBundleGetter{
			URL:			bundleURL,
			InsecureSkipVerify:	gw.GetConfig().BundleInsecureSkipVerify,
		}
	default:
		err = errors.New("Unknown URL scheme")
	}
	if err != nil {
		return bundle, err
	}

	bundleData, err := pullBundle(getter, bundleBackoffMultiplier)

	bundle.Name = spec.CustomMiddlewareBundle
	bundle.Data = bundleData
	bundle.Spec = spec
	return bundle, err
}

Cognitive complexity: 16, Cyclomatic complexity: 8

Uses: errors.New, logrus.Fields, path.Join, url.Parse.

func (*Gateway) FireSystemEvent

func (gw *Gateway) FireSystemEvent(name apidef.TykEvent, meta interface{}) {
	fireEvent(name, meta, gw.GetConfig().GetEventTriggers())
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*Gateway) GetApiSpecsFromAccessRights

GetApiSpecsFromAccessRights from the session.AccessRights returns the collection of api specs

func (gw *Gateway) GetApiSpecsFromAccessRights(sess *user.SessionState) []*APISpec {
	var apis []*APISpec
	if sess != nil && len(sess.AccessRights) > 0 {
		for apiID := range sess.AccessRights {
			spec := gw.getApiSpec(apiID)
			if spec != nil {
				apis = append(apis, spec)
			}
		}
	}

	return apis
}

Cognitive complexity: 7, Cyclomatic complexity: 5

func (*Gateway) GetCoProcessGrpcServerTargetURL

func (gw *Gateway) GetCoProcessGrpcServerTargetURL() (*url.URL, error) {
	grpcURL, err := url.Parse(gw.GetConfig().CoProcessOptions.CoProcessGRPCServer)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error(err)
		return nil, err
	}

	if grpcURL == nil || gw.GetConfig().CoProcessOptions.CoProcessGRPCServer == "" {
		errString := "No gRPC URL is set!"
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error(errString)
		return nil, err
	}
	return grpcURL, nil
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: logrus.Fields, url.Parse.

func (*Gateway) GetConfig

func (gw *Gateway) GetConfig() config.Config {
	return gw.config.Load().(config.Config)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: config.Config.

func (*Gateway) GetNodeID

GetNodeID reads NodeID safely.

func (gw *Gateway) GetNodeID() string {
	gw.nodeIDMu.Lock()
	defer gw.nodeIDMu.Unlock()
	return gw.nodeID
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Gateway) GetStorageForApi

func (gw *Gateway) GetStorageForApi(apiID string) (ExtendedOsinStorageInterface, int, error) {
	apiSpec := gw.getApiSpec(apiID)
	if apiSpec == nil {
		log.WithFields(logrus.Fields{
			"prefix":	"api",
			"apiID":	apiID,
			"status":	"fail",
			"err":		"API not found",
		}).Error("Failed to retrieve OAuth client list.")

		return nil, http.StatusNotFound, errors.New(oAuthClientNotFound)
	}

	if apiSpec.OAuthManager == nil {
		log.WithFields(logrus.Fields{
			"prefix":	"api",
			"apiID":	apiID,
			"status":	"fail",
			"err":		"API not found",
		}).Error("Failed to revoke client tokens.")

		return nil, http.StatusNotFound, errors.New(oAuthNotPropagatedErr)
	}

	return apiSpec.OAuthManager.Storage(), http.StatusOK, nil
}

Cognitive complexity: 6, Cyclomatic complexity: 3

Uses: errors.New, http.StatusNotFound, http.StatusOK, logrus.Fields.

func (*Gateway) InitHostCheckManager

func (gw *Gateway) InitHostCheckManager(ctx context.Context, store storage.Handler) {
	// Already initialized
	if gw.GlobalHostChecker != nil {
		return
	}

	gw.GlobalHostChecker = &HostCheckerManager{Gw: gw}
	gw.GlobalHostChecker.Init(store)
	gw.GlobalHostChecker.Start(ctx)
}

Cognitive complexity: 3, Cyclomatic complexity: 2

func (*Gateway) LoadAPI

func (gw *Gateway) LoadAPI(specs ...*APISpec) (out []*APISpec) {
	var err error
	gwConf := gw.GetConfig()
	oldPath := gwConf.AppPath
	gwConf.AppPath, err = ioutil.TempDir("", "apps")
	if err != nil {
		log.WithError(err).Errorf("loadapi: failed to create temp dir")
	}
	gw.SetConfig(gwConf, true)
	defer func() {
		globalConf := gw.GetConfig()
		os.RemoveAll(globalConf.AppPath)
		globalConf.AppPath = oldPath
		gw.SetConfig(globalConf, true)
	}()

	for i, spec := range specs {
		if spec.Name == "" {
			spec.Name = randStringBytes(15)
		}

		specBytes, err := json.Marshal(spec.APIDefinition)
		if err != nil {
			log.WithError(err).Errorf("API Spec Marshal failed: %+v", spec)
			panic(err)
		}

		specFilePath := filepath.Join(gwConf.AppPath, spec.APIID+strconv.Itoa(i)+".json")
		if err := ioutil.WriteFile(specFilePath, specBytes, 0644); err != nil {
			panic(err)
		}

		oasSpecBytes, err := json.Marshal(&spec.OAS)
		if err != nil {
			log.WithError(err).Errorf("OAS Marshal failed: %+v", spec)
			panic(err)
		}

		oasSpecFilePath := filepath.Join(gwConf.AppPath, spec.APIID+strconv.Itoa(i)+"-oas.json")
		if err := ioutil.WriteFile(oasSpecFilePath, oasSpecBytes, 0644); err != nil {
			panic(err)
		}
	}

	gw.DoReload()
	for _, spec := range specs {
		out = append(out, gw.getApiSpec(spec.APIID))
	}

	return out
}

Cognitive complexity: 19, Cyclomatic complexity: 9

Uses: filepath.Join, ioutil.TempDir, ioutil.WriteFile, json.Marshal, os.RemoveAll, strconv.Itoa.

func (*Gateway) LoadDefinitionsFromRPCBackup

func (gw *Gateway) LoadDefinitionsFromRPCBackup() ([]*APISpec, error) {
	tagList := getTagListAsString(gw.GetConfig().DBAppConfOptions.Tags)
	checkKey := BackupApiKeyBase + tagList

	store := &storage.RedisCluster{KeyPrefix: RPCKeyPrefix, ConnectionHandler: gw.StorageConnectionHandler}
	connected := store.Connect()

	log.Info("[RPC] --> Loading API definitions from backup")

	if !connected {
		return nil, errors.New("[RPC] --> RPC Backup recovery failed: redis connection failed")
	}

	secret := crypto.GetPaddedString(gw.GetConfig().Secret)
	cryptoText, err := store.GetKey(checkKey)
	if err != nil {
		return nil, errors.New("[RPC] --> Failed to get node backup (" + checkKey + "): " + err.Error())
	}

	apiListAsString := crypto.Decrypt([]byte(secret), cryptoText)

	a := APIDefinitionLoader{Gw: gw}
	return a.processRPCDefinitions(apiListAsString, gw)
}

Cognitive complexity: 6, Cyclomatic complexity: 3

Uses: crypto.Decrypt, crypto.GetPaddedString, errors.New, storage.RedisCluster.

func (*Gateway) LoadPoliciesFromDashboard

LoadPoliciesFromDashboard will connect and download Policies from a Tyk Dashboard instance.

func (gw *Gateway) LoadPoliciesFromDashboard(endpoint, secret string, allowExplicit bool) (map[string]user.Policy, error) {

	// Get the definitions
	newRequest, err := http.NewRequest("GET", endpoint, nil)
	if err != nil {
		log.Error("Failed to create request: ", err)
		return nil, err
	}

	newRequest.Header.Set("authorization", secret)
	newRequest.Header.Set(header.XTykNodeID, gw.GetNodeID())
	newRequest.Header.Set(header.XTykSessionID, gw.SessionID)

	gw.ServiceNonceMutex.RLock()
	newRequest.Header.Set("x-tyk-nonce", gw.ServiceNonce)
	gw.ServiceNonceMutex.RUnlock()

	log.WithFields(logrus.Fields{
		"prefix": "policy",
	}).Info("Mutex lock acquired... calling")
	c := gw.initialiseClient()

	log.WithFields(logrus.Fields{
		"prefix": "policy",
	}).Info("Calling dashboard service for policy list")
	resp, err := c.Do(newRequest)
	if err != nil {
		log.Error("Policy request failed: ", err)
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := ioutil.ReadAll(resp.Body)
		log.Error("Policy request login failure, Response was: ", string(body))
		return nil, ErrPoliciesFetchFailed
	}

	// Extract Policies
	var list struct {
		Message	[]DBPolicy
		Nonce	string
	}
	if err := json.NewDecoder(resp.Body).Decode(&list); err != nil {
		log.Error("Failed to decode policy body: ", err)
		return nil, err
	}

	gw.ServiceNonceMutex.Lock()
	gw.ServiceNonce = list.Nonce
	gw.ServiceNonceMutex.Unlock()
	log.Debug("Loading Policies Finished: Nonce Set: ", list.Nonce)

	policies := make(map[string]user.Policy, len(list.Message))

	log.WithFields(logrus.Fields{
		"prefix": "policy",
	}).Info("Processing policy list")
	for _, p := range list.Message {
		id := p.MID.Hex()
		if allowExplicit && p.ID != "" {
			id = p.ID
		}
		p.ID = id
		if _, ok := policies[id]; ok {
			log.WithFields(logrus.Fields{
				"prefix":	"policy",
				"policyID":	p.ID,
				"OrgID":	p.OrgID,
			}).Warning("--> Skipping policy, new item has a duplicate ID!")
			continue
		}
		policies[id] = p.ToRegularPolicy()
	}

	return policies, err
}

Cognitive complexity: 20, Cyclomatic complexity: 9

Uses: header.XTykNodeID, header.XTykSessionID, http.NewRequest, http.StatusOK, ioutil.ReadAll, json.NewDecoder, logrus.Fields, user.Policy.

func (*Gateway) LoadPoliciesFromRPC

func (gw *Gateway) LoadPoliciesFromRPC(store RPCDataLoader, orgId string, allowExplicit bool) (map[string]user.Policy, error) {
	if rpc.IsEmergencyMode() {
		return gw.LoadPoliciesFromRPCBackup()
	}

	if !store.Connect() {
		return nil, errors.New("Policies backup: Failed connecting to database")
	}

	rpcPolicies := store.GetPolicies(orgId)

	policies, err := parsePoliciesFromRPC(rpcPolicies, allowExplicit)

	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "policy",
		}).Error("Failed decode: ", err, rpcPolicies)
		return nil, err
	}

	if err := gw.saveRPCPoliciesBackup(rpcPolicies); err != nil {
		log.Error(err)
	}

	return policies, nil
}

Cognitive complexity: 9, Cyclomatic complexity: 5

Uses: errors.New, logrus.Fields, rpc.IsEmergencyMode.

func (*Gateway) LoadPoliciesFromRPCBackup

func (gw *Gateway) LoadPoliciesFromRPCBackup() (map[string]user.Policy, error) {
	tagList := getTagListAsString(gw.GetConfig().DBAppConfOptions.Tags)
	checkKey := BackupPolicyKeyBase + tagList

	store := &storage.RedisCluster{KeyPrefix: RPCKeyPrefix, ConnectionHandler: gw.StorageConnectionHandler}
	connected := store.Connect()

	log.Info("[RPC] Loading Policies from backup")

	if !connected {
		return nil, errors.New("[RPC] --> RPC Policy Backup recovery failed: redis connection failed")
	}

	secret := crypto.GetPaddedString(gw.GetConfig().Secret)
	cryptoText, err := store.GetKey(checkKey)
	listAsString := crypto.Decrypt([]byte(secret), cryptoText)

	if err != nil {
		return nil, errors.New("[RPC] --> Failed to get node policy backup (" + checkKey + "): " + err.Error())
	}

	if policies, err := parsePoliciesFromRPC(listAsString, gw.GetConfig().Policies.AllowExplicitPolicyID); err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "policy",
		}).Error("Failed decode: ", err)
		return nil, err
	} else {
		return policies, nil
	}
}

Cognitive complexity: 10, Cyclomatic complexity: 4

Uses: crypto.Decrypt, crypto.GetPaddedString, errors.New, logrus.Fields, storage.RedisCluster.

func (*Gateway) LoadSampleAPI

func (gw *Gateway) LoadSampleAPI(def string) (spec *APISpec) {
	spec = gw.CreateDefinitionFromString(def)
	gw.loadApps([]*APISpec{spec})
	return
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*Gateway) MarshalJSON

func (gw *Gateway) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct{}{})
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: json.Marshal.

func (*Gateway) MonitorApplicationInstrumentation

func (gw *Gateway) MonitorApplicationInstrumentation() {
	log.Info("Starting application monitoring...")
	go func() {
		job := instrument.NewJob("GCActivity")
		job_rl := instrument.NewJob("Load")
		metadata := health.Kvs{"host": gw.hostDetails.Hostname}
		applicationGCStats.PauseQuantiles = make([]time.Duration, 5)

		for {
			debug.ReadGCStats(&applicationGCStats)
			job.GaugeKv("pauses_quantile_min", float64(applicationGCStats.PauseQuantiles[0].Nanoseconds()), metadata)
			job.GaugeKv("pauses_quantile_25", float64(applicationGCStats.PauseQuantiles[1].Nanoseconds()), metadata)
			job.GaugeKv("pauses_quantile_50", float64(applicationGCStats.PauseQuantiles[2].Nanoseconds()), metadata)
			job.GaugeKv("pauses_quantile_75", float64(applicationGCStats.PauseQuantiles[3].Nanoseconds()), metadata)
			job.GaugeKv("pauses_quantile_max", float64(applicationGCStats.PauseQuantiles[4].Nanoseconds()), metadata)

			job_rl.GaugeKv("rps", float64(GlobalRate.Rate()), metadata)
			time.Sleep(5 * time.Second)
		}
	}()
}

Cognitive complexity: 4, Cyclomatic complexity: 2

Uses: debug.ReadGCStats, health.Kvs, time.Duration, time.Second, time.Sleep.

func (*Gateway) NewGRPCDispatcher

NewGRPCDispatcher wraps all the actions needed for this CP.

func (gw *Gateway) NewGRPCDispatcher() (coprocess.Dispatcher, error) {
	if gw.GetConfig().CoProcessOptions.CoProcessGRPCServer == "" {
		return nil, errors.New("No gRPC URL is set")
	}

	var err error
	grpcUrl, err := gw.GetCoProcessGrpcServerTargetURL()
	if err != nil {
		return nil, err
	}

	dialOptions := []grpc.DialOption{gw.grpcCallOpts(), grpc.WithTransportCredentials(insecure.NewCredentials())}
	authority := gw.GetConfig().CoProcessOptions.GRPCAuthority
	if authority != "" {
		dialOptions = append(dialOptions, grpc.WithAuthority(authority))
	}

	grpcConnection, err = grpc.NewClient(
		GetCoProcessGrpcServerTargetUrlAsString(grpcUrl),
		dialOptions...,
	)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "coprocess",
		}).Error(err)
		return nil, err
	}

	grpcClient = coprocess.NewDispatcherClient(grpcConnection)
	return &GRPCDispatcher{}, nil
}

Cognitive complexity: 11, Cyclomatic complexity: 5

Uses: coprocess.NewDispatcherClient, errors.New, grpc.DialOption, grpc.NewClient, grpc.WithAuthority, grpc.WithTransportCredentials, insecure.NewCredentials, logrus.Fields.

func (*Gateway) NewMultiTargetProxy

func (gw *Gateway) NewMultiTargetProxy(spec *APISpec, logger *logrus.Entry) *MultiTargetProxy {
	m := &MultiTargetProxy{}
	m.versionProxies = make(map[string]*ReverseProxy)
	m.specReference = spec
	m.defaultProxy = gw.TykNewSingleHostReverseProxy(spec.target, spec, logger)

	for vname, vdata := range spec.VersionData.Versions {
		if vdata.OverrideTarget == "" {
			log.WithFields(logrus.Fields{
				"prefix": "multi-target",
			}).Info("----> Version ", vname, " has no override target")
			m.versionProxies[vname] = m.defaultProxy
			continue
		}
		remote, err := url.Parse(vdata.OverrideTarget)
		log.WithFields(logrus.Fields{
			"prefix": "multi-target",
		}).Info("----> Version ", vname, " has '", vdata.OverrideTarget, "' for override target")
		log.WithFields(logrus.Fields{
			"prefix": "multi-target",
		}).Debug("Multi-target URL: ", vdata.OverrideTarget)
		log.WithFields(logrus.Fields{
			"prefix": "multi-target",
		}).Debug("Multi-target URL (obj): ", remote)
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix": "multi-target",
			}).Error("Couldn't parse version target URL in MultiTarget: ", err)
		}
		m.versionProxies[vname] = gw.TykNewSingleHostReverseProxy(remote, spec, logger)
	}
	return m
}

Cognitive complexity: 13, Cyclomatic complexity: 4

Uses: logrus.Fields, url.Parse.

func (*Gateway) NotifyCurrentServerStatus

func (gw *Gateway) NotifyCurrentServerStatus() {
	if !gw.DRLManager.Ready() {
		return
	}

	rate := GlobalRate.Rate()
	if rate == 0 {
		rate = 1
	}

	server := drl.Server{
		HostName:	gw.hostDetails.Hostname,
		ID:		gw.GetNodeID(),
		LoadPerSec:	rate,
		TagHash:	gw.getTagHash(),
	}

	asJson, err := json.Marshal(server)
	if err != nil {
		log.Error("Failed to encode payload: ", err)
		return
	}

	n := Notification{
		Command:	NoticeGatewayDRLNotification,
		Payload:	string(asJson),
		Gw:		gw,
	}

	gw.MainNotifier.Notify(n)
}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: drl.Server, json.Marshal.

func (*Gateway) PolicyByID

PolicyByID will return a Policy matching the passed Policy ID.

func (gw *Gateway) PolicyByID(id string) (user.Policy, bool) {
	gw.policiesMu.RLock()
	defer gw.policiesMu.RUnlock()

	pol, ok := gw.policiesByID[id]
	return pol, ok
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Gateway) PolicyCount

PolicyCount will return the number of policies loaded in the gateway.

func (gw *Gateway) PolicyCount() int {
	gw.policiesMu.RLock()
	defer gw.policiesMu.RUnlock()

	return len(gw.policiesByID)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Gateway) PolicyIDs

PolicyIDs returns a list of IDs for each policy loaded in the gateway.

func (gw *Gateway) PolicyIDs() []string {
	gw.policiesMu.RLock()
	defer gw.policiesMu.RUnlock()

	result := make([]string, 0, len(gw.policiesByID))
	for id := range gw.policiesByID {
		result = append(result, id)
	}
	return result
}

Cognitive complexity: 3, Cyclomatic complexity: 2

func (*Gateway) ProcessOauthClientsOps

ProcessOauthClientsOps performs the appropriate action for the received clients it can be any of the Create,Update and Delete operations

func (gw *Gateway) ProcessOauthClientsOps(clients map[string]string) {
	for clientInfo, action := range clients {
		// clientInfo is: APIID.ClientID.OrgID
		eventValues := strings.Split(clientInfo, ".")
		apiId := eventValues[0]
		oauthClientId := eventValues[1]
		orgID := eventValues[2]

		gw.ProcessSingleOauthClientEvent(apiId, oauthClientId, orgID, action)
	}
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: strings.Split.

func (*Gateway) ProcessSingleOauthClientEvent

func (gw *Gateway) ProcessSingleOauthClientEvent(apiId, oauthClientId, orgID, event string) {
	store, _, err := gw.GetStorageForApi(apiId)
	if err != nil {
		log.Error("Could not get oauth storage for api")
		return
	}

	switch event {
	case OauthClientAdded:
		// on add: pull from rpc and save it in local redis
		client, err := store.GetClient(oauthClientId)
		if err != nil {
			log.WithError(err).Error("Could not retrieve new oauth client information")
			return
		}

		err = store.SetClient(oauthClientId, orgID, client, false)
		if err != nil {
			log.WithError(err).Error("Could not save oauth client.")
			return
		}

		log.Info("oauth client created successfully")
	case OauthClientRemoved:
		// on remove: remove from local redis
		err := store.DeleteClient(oauthClientId, orgID, false)
		if err != nil {
			log.Errorf("Could not delete oauth client with id: %v", oauthClientId)
			return
		}
		log.Infof("Oauth Client deleted successfully")
	case OauthClientUpdated:
		// on update: delete from local redis and pull again from rpc
		_, err := store.GetClient(oauthClientId)
		if err != nil {
			log.WithError(err).Error("Could not retrieve oauth client information")
			return
		}

		err = store.DeleteClient(oauthClientId, orgID, false)
		if err != nil {
			log.WithError(err).Error("Could not delete oauth client")
			return
		}

		client, err := store.GetClient(oauthClientId)
		if err != nil {
			log.WithError(err).Error("Could not retrieve oauth client information")
			return
		}

		err = store.SetClient(oauthClientId, orgID, client, false)
		if err != nil {
			log.WithError(err).Error("Could not save oauth client.")
			return
		}
		log.Info("oauth client updated successfully")
	default:
		log.Warningf("Oauth client event not supported:%v", event)
	}
}

Cognitive complexity: 21, Cyclomatic complexity: 13

func (*Gateway) ReplaceTykVariables

ReplaceTykVariables implements a variable replacement hook. It will replace the template in. If escape is true, the values get escaped as a query parameter for a HTTP request would. If no replacement has been made, in is returned without modification.

func (gw *Gateway) ReplaceTykVariables(r *http.Request, in string, escape bool) string {

	if strings.Contains(in, secretsConfLabel) {
		contextData := ctxGetData(r)
		vars := secretsConfMatch.FindAllString(in, -1)
		in = gw.replaceVariables(in, vars, contextData, secretsConfLabel, escape)
	}

	if strings.Contains(in, envLabel) {
		contextData := ctxGetData(r)
		vars := envValueMatch.FindAllString(in, -1)
		in = gw.replaceVariables(in, vars, contextData, envLabel, escape)
	}

	if strings.Contains(in, vaultLabel) {
		contextData := ctxGetData(r)
		vars := vaultMatch.FindAllString(in, -1)
		in = gw.replaceVariables(in, vars, contextData, vaultLabel, escape)
	}

	if strings.Contains(in, consulLabel) {
		contextData := ctxGetData(r)
		vars := consulMatch.FindAllString(in, -1)
		in = gw.replaceVariables(in, vars, contextData, consulLabel, escape)
	}

	if strings.Contains(in, contextLabel) {
		contextData := ctxGetData(r)
		vars := contextMatch.FindAllString(in, -1)
		in = gw.replaceVariables(in, vars, contextData, contextLabel, escape)
	}

	if strings.Contains(in, metaLabel) {
		vars := metaMatch.FindAllString(in, -1)
		session := ctxGetSession(r)
		if session == nil {
			in = gw.replaceVariables(in, vars, nil, metaLabel, escape)
		} else {
			in = gw.replaceVariables(in, vars, session.MetaData, metaLabel, escape)
		}
	}
	//todo add config_data
	return in
}

Cognitive complexity: 16, Cyclomatic complexity: 8

Uses: strings.Contains.

func (*Gateway) RevokeAllTokensHandler

func (gw *Gateway) RevokeAllTokensHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()

	if err != nil {
		doJSONWrite(w, http.StatusBadRequest, apiError("cannot parse form. Form malformed"))
		return
	}

	clientId := r.PostFormValue("client_id")
	clientSecret := r.PostFormValue("client_secret")
	orgId := r.PostFormValue("org_id")

	if clientId == "" {
		doJSONWrite(w, http.StatusUnauthorized, apiError(oauthClientIdEmpty))
		return
	}

	if clientSecret == "" {
		doJSONWrite(w, http.StatusUnauthorized, apiError(oauthClientSecretEmpty))
		return
	}

	apis := gw.getApisForOauthClientId(clientId, orgId)
	if len(apis) == 0 {
		//if api is 0 is because the client wasn't found
		doJSONWrite(w, http.StatusNotFound, apiError("oauth client doesn't exist"))
		return
	}

	tokens := []string{}
	for _, apiId := range apis {
		storage, _, err := gw.GetStorageForApi(apiId)
		if err == nil {
			_, tokensRevoked, _ := RevokeAllTokens(storage, clientId, clientSecret)
			tokens = append(tokens, tokensRevoked...)
		}
	}

	n := Notification{
		Command:	KeySpaceUpdateNotification,
		Payload:	strings.Join(tokens, ","),
		Gw:		gw,
	}
	gw.MainNotifier.Notify(n)

	doJSONWrite(w, http.StatusOK, apiOk("tokens revoked successfully"))
}

Cognitive complexity: 15, Cyclomatic complexity: 7

Uses: http.StatusBadRequest, http.StatusNotFound, http.StatusOK, http.StatusUnauthorized, strings.Join.

func (*Gateway) RevokeTokenHandler

func (gw *Gateway) RevokeTokenHandler(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()

	if err != nil {
		doJSONWrite(w, http.StatusBadRequest, apiError("cannot parse form. Form malformed"))
		return
	}

	tokenTypeHint := r.PostFormValue("token_type_hint")
	token := r.PostFormValue("token")
	clientID := r.PostFormValue("client_id")
	orgID := r.PostFormValue("org_id")

	if token == "" {
		doJSONWrite(w, http.StatusBadRequest, apiError(oauthTokenEmpty))
		return
	}

	if clientID == "" {
		doJSONWrite(w, http.StatusBadRequest, apiError(oauthClientIdEmpty))
		return
	}

	apis := gw.getApisForOauthClientId(clientID, orgID)
	if len(apis) == 0 {
		doJSONWrite(w, http.StatusBadRequest, apiError("oauth client doesn't exist"))
		return
	}

	for _, apiID := range apis {
		storage, _, err := gw.GetStorageForApi(apiID)
		if err == nil {
			RevokeToken(storage, token, tokenTypeHint)
		}
	}
	doJSONWrite(w, http.StatusOK, apiOk("token revoked successfully"))
}

Cognitive complexity: 13, Cyclomatic complexity: 7

Uses: http.StatusBadRequest, http.StatusOK.

func (*Gateway) SetCheckerHostList

func (gw *Gateway) SetCheckerHostList() {
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Info("Loading uptime tests...")
	hostList := []HostData{}
	gw.apisMu.RLock()
	for _, spec := range gw.apisByID {
		gw.populateHostListByApiSpec(&hostList, spec)
	}
	gw.apisMu.RUnlock()

	gw.GlobalHostChecker.UpdateTrackingList(hostList)
}

Cognitive complexity: 5, Cyclomatic complexity: 2

Uses: logrus.Fields.

func (*Gateway) SetConfig

func (gw *Gateway) SetConfig(conf config.Config, skipReload ...bool) {
	gw.configMu.Lock()
	gw.config.Store(conf)
	gw.configMu.Unlock()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Gateway) SetNodeID

SetNodeID writes NodeID safely.

func (gw *Gateway) SetNodeID(nodeID string) {
	gw.nodeIDMu.Lock()
	gw.nodeID = nodeID
	gw.nodeIDMu.Unlock()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Gateway) SetPolicies

SetPolicies updates the internal policy map with a new policy map.

func (gw *Gateway) SetPolicies(pols map[string]user.Policy) {
	gw.policiesMu.Lock()
	defer gw.policiesMu.Unlock()

	gw.policiesByID = pols
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Gateway) SetPoliciesByID

SetPoliciesByID will update the internal policiesByID map with new policies. The key used will be the policy ID.

func (gw *Gateway) SetPoliciesByID(pols ...user.Policy) {
	gw.policiesMu.Lock()
	defer gw.policiesMu.Unlock()

	for _, pol := range pols {
		gw.policiesByID[pol.ID] = pol
	}
}

Cognitive complexity: 3, Cyclomatic complexity: 2

func (*Gateway) SetupNewRelic

SetupNewRelic creates new newrelic.Application instance.

func (gw *Gateway) SetupNewRelic() (app *newrelic.Application) {
	var (
		err		error
		gwConfig	= gw.GetConfig()
	)

	log := log.WithFields(logrus.Fields{"prefix": "newrelic"})

	cfg := []newrelic.ConfigOption{
		newrelic.ConfigAppName(gwConfig.NewRelic.AppName),
		newrelic.ConfigLicense(gwConfig.NewRelic.LicenseKey),
		newrelic.ConfigEnabled(gwConfig.NewRelic.AppName != ""),
		newrelic.ConfigDistributedTracerEnabled(gwConfig.NewRelic.EnableDistributedTracing),
		newrelic.ConfigLogger(newrelic.NewLogger(log)),
	}

	if app, err = newrelic.NewApplication(cfg...); err != nil {
		log.Warn("Error initializing NewRelic, skipping... ", err)
		return
	}

	instrument.AddSink(newrelic.NewSink(app))

	return
}

Cognitive complexity: 4, Cyclomatic complexity: 2

Uses: logrus.Fields, newrelic.ConfigAppName, newrelic.ConfigDistributedTracerEnabled, newrelic.ConfigEnabled, newrelic.ConfigLicense, newrelic.ConfigLogger, newrelic.ConfigOption, newrelic.NewApplication, newrelic.NewLogger, newrelic.NewSink.

func (*Gateway) SignatureVerifier

SignatureVerifier returns a verifier to use for validating signatures. It is configured with the PublicKeyPath value in gateway config.

func (gw *Gateway) SignatureVerifier() (goverify.Verifier, error) {
	gwConfig := gw.GetConfig()
	if gwConfig.PublicKeyPath == "" {
		return nil, nil
	}

	cached := gw.signatureVerifier.Load()
	if cached != nil {
		return *cached, nil
	}

	log.Warnf("Creating new NotificationVerifier with pubkey: %q", gwConfig.PublicKeyPath)

	verifier, err := goverify.LoadPublicKeyFromFile(gwConfig.PublicKeyPath)
	if err != nil {
		mainLog.WithError(err).Errorf("Failed loading public key from path: %s", err)
		return nil, err
	}

	gw.signatureVerifier.Store(&verifier)
	return verifier, nil
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: goverify.LoadPublicKeyFromFile.

func (*Gateway) TykNewSingleHostReverseProxy

TykNewSingleHostReverseProxy returns a new ReverseProxy that rewrites URLs to the scheme, host, and base path provided in target. If the target's path is "/base" and the incoming request was for "/dir", the target request will be for /base/dir. This version modifies the stdlib version by also setting the host to the target, this allows us to work with heroku and other such providers

func (gw *Gateway) TykNewSingleHostReverseProxy(target *url.URL, spec *APISpec, logger *logrus.Entry) *ReverseProxy {
	onceStartAllHostsDown.Do(func() {
		handler := func(w http.ResponseWriter, r *http.Request) {
			http.Error(w, "all hosts are down", http.StatusServiceUnavailable)
		}
		listener, err := net.Listen("tcp", "127.0.0.1:0")
		if err != nil {
			panic(err)
		}
		server := &http.Server{
			Handler:	http.HandlerFunc(handler),
			ReadTimeout:	1 * time.Second,
			WriteTimeout:	1 * time.Second,
			MaxHeaderBytes:	1 << 20,
		}
		allHostsDownURL = "http://" + listener.Addr().String()
		go func() {
			panic(server.Serve(listener))
		}()
	})

	if logger == nil {
		logger = logrus.NewEntry(log)
	}

	logger = logger.WithField("mw", "ReverseProxy")

	targetQuery := target.RawQuery
	director := func(req *http.Request) {
		logger := logger
		spec := spec
		target := target
		gw := gw

		hostList := spec.Proxy.StructuredTargetList
		switch {
		case spec.Proxy.ServiceDiscovery.UseDiscoveryService:
			var err error
			hostList, err = urlFromService(spec, gw)
			if err != nil {
				logger.Error("[PROXY] [SERVICE DISCOVERY] Failed target lookup: ", err)
				break
			}
			fallthrough	// implies load balancing, with replaced host list
		case spec.Proxy.EnableLoadBalancing:
			host, err := gw.nextTarget(hostList, spec)
			if err != nil {
				logger.Error("[PROXY] [LOAD BALANCING] ", err)
				host = allHostsDownURL
			}
			lbRemote, err := url.Parse(host)
			if err != nil {
				logger.Error("[PROXY] [LOAD BALANCING] Couldn't parse target URL:", err)
			} else {
				// Only replace target if everything is OK
				target = lbRemote
				targetQuery = target.RawQuery
			}
		}

		targetToUse := target

		if spec.URLRewriteEnabled && req.Context().Value(ctx.RetainHost) == true {
			logger.Debug("Detected host rewrite, overriding target")
			tmpTarget, err := url.Parse(req.URL.String())
			if err != nil {
				logger.Error("Failed to parse URL! Err: ", err)
			} else {
				// Specifically override with a URL rewrite
				targetToUse = tmpTarget
			}
		}

		// No override, and no load balancing? Use the existing target

		// if this is false, there was an url rewrite, thus we
		// don't want to do anything to the path - req.URL is
		// already final.
		if targetToUse == target {
			req.URL.Scheme = targetToUse.Scheme
			req.URL.Host = targetToUse.Host
			req.URL.Path = singleJoiningSlash(targetToUse.Path, req.URL.Path, spec.Proxy.DisableStripSlash)
			if req.URL.RawPath != "" {
				req.URL.RawPath = singleJoiningSlash(targetToUse.Path, req.URL.RawPath, spec.Proxy.DisableStripSlash)
			}
		}

		if !spec.Proxy.PreserveHostHeader {
			req.Host = targetToUse.Host
		}

		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
		}
		if _, ok := req.Header[header.UserAgent]; !ok {
			// Set Tyk's own default user agent. Without
			// this line, we would get the net/http default.
			req.Header.Set(header.UserAgent, defaultUserAgent)
		}

		if spec.GlobalConfig.HttpServerOptions.SkipTargetPathEscaping {
			// force RequestURI to skip escaping if API's proxy is set for this
			// if we set opaque here it will force URL.RequestURI to skip escaping
			if req.URL.RawPath != "" {
				req.URL.Opaque = req.URL.RawPath
			}
		} else if req.URL.RawPath == req.URL.Path {
			// this should force URL to do escaping
			req.URL.RawPath = ""
		}

		switch req.URL.Scheme {
		case "ws":
			req.URL.Scheme = "http"
		case "wss":
			req.URL.Scheme = "https"
		}
	}

	proxy := &ReverseProxy{
		Director:	director,
		TykAPISpec:	spec,
		FlushInterval:	time.Duration(spec.GlobalConfig.HttpServerOptions.FlushInterval) * time.Millisecond,
		logger:		logger,
		wsUpgrader: websocket.Upgrader{
			// CheckOrigin is not needed for the upgrader as tyk already provides
			// its own middlewares for that.
			CheckOrigin: func(r *http.Request) bool {
				return true
			},
		},
		sp: sync.Pool{
			New: func() interface{} {
				buffer := make([]byte, 32*1024)
				return &buffer
			},
		},
		Gw:	gw,
	}
	proxy.ErrorHandler.BaseMiddleware = &BaseMiddleware{Spec: spec, Proxy: proxy, Gw: gw}
	return proxy
}

Cognitive complexity: 12, Cyclomatic complexity: 2

Uses: ctx.RetainHost, header.UserAgent, http.Error, http.HandlerFunc, http.Request, http.ResponseWriter, http.Server, http.StatusServiceUnavailable, logrus.NewEntry, net.Listen, sync.Pool, time.Duration, time.Millisecond, time.Second, url.Parse, websocket.Upgrader.

func (*Gateway) TykOsinNewServer

TykOsinNewServer creates a new server instance, but uses an extended interface so we can SetClient() too.

func (gw *Gateway) TykOsinNewServer(config *osin.ServerConfig, storage ExtendedOsinStorageInterface) *TykOsinServer {

	overrideServer := TykOsinServer{
		Config:			config,
		Storage:		storage,
		AuthorizeTokenGen:	&osin.AuthorizeTokenGenDefault{},
		AccessTokenGen:		accessTokenGen{gw},
	}

	overrideServer.Server.Config = config
	overrideServer.Server.Storage = storage
	overrideServer.Server.AuthorizeTokenGen = overrideServer.AuthorizeTokenGen
	overrideServer.Server.AccessTokenGen = accessTokenGen{gw}

	return &overrideServer
}

Cognitive complexity: 4, Cyclomatic complexity: 1

Uses: osin.AuthorizeTokenGenDefault.

func (*Gateway) UnmarshalJSON

func (gw *Gateway) UnmarshalJSON(data []byte) error {
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GoPluginMiddleware) EnabledForSpec

func (m *GoPluginMiddleware) EnabledForSpec() bool {
	// global go plugins
	if m.Path != "" && m.SymbolName != "" {
		m.loadPlugin()
		return true
	}

	// per path go plugins
	for _, version := range m.Spec.VersionData.Versions {
		for _, p := range version.ExtendedPaths.GoPlugin {
			if !p.Disabled {
				return true
			}
		}
	}

	return false
}

Cognitive complexity: 10, Cyclomatic complexity: 6

func (*GoPluginMiddleware) Name

func (m *GoPluginMiddleware) Name() string {
	return "GoPluginMiddleware: " + m.Path + ":" + m.SymbolName
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GoPluginMiddleware) ProcessRequest

func (m *GoPluginMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (err error, respCode int) {
	logger := m.logger
	handler := m.handler
	successHandler := m.successHandler

	if !m.APILevel {
		// if a Go plugin is found for this path, override the base handler and logger
		if pluginMw, found := m.goPluginFromRequest(r); found {
			logger = pluginMw.logger
			handler = pluginMw.handler
			successHandler = &SuccessHandler{BaseMiddleware: m.BaseMiddleware.Copy()}
		} else {
			return nil, http.StatusOK	// next middleware
		}
	}

	if handler == nil {
		respCode = http.StatusInternalServerError
		err = errors.New(http.StatusText(respCode))
		return
	}

	// make sure tyk recover in case Go-plugin function panics
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("%v", e)
			respCode = http.StatusInternalServerError
			logger.WithError(err).Error("Recovered from panic while running Go-plugin middleware func")
		}
	}()

	// prepare data to call Go-plugin function

	// make sure request's body can be re-read again
	nopCloseRequestBody(r)

	// wrap ResponseWriter to check if response was sent
	rw := &customResponseWriter{
		ResponseWriter:	w,
		copyData:	recordDetail(r, m.Spec),
	}

	// call Go-plugin function
	t1 := time.Now()

	// Inject definition into request context:
	m.Spec.injectIntoReqContext(r)

	handler(rw, r)
	if session := ctxGetSession(r); session != nil {
		if err := m.ApplyPolicies(session); err != nil {
			m.Logger().WithError(err).Error("Could not apply policy to session")
			return errors.New(http.StatusText(http.StatusInternalServerError)), http.StatusInternalServerError
		}
	}

	// calculate latency
	ms := DurationToMillisecond(time.Since(t1))
	logger.WithField("ms", ms).Debug("Go-plugin request processing took")

	// check if response was sent
	if rw.responseSent {
		// check if response code was an error one
		switch {
		case rw.statusCodeSent == http.StatusForbidden:
			logger.WithError(err).Error("Authentication error in Go-plugin middleware func")
			m.Base().FireEvent(EventAuthFailure, EventKeyFailureMeta{
				EventMetaDefault:	EventMetaDefault{Message: "Auth Failure", OriginatingRequest: EncodeRequestToEvent(r)},
				Path:			r.URL.Path,
				Origin:			request.RealIP(r),
				Key:			"n/a",
			})
			fallthrough
		case rw.statusCodeSent >= http.StatusBadRequest:
			// base middleware will report this error to analytics if needed
			respCode = rw.statusCodeSent
			err = fmt.Errorf("plugin function sent error response code: %d", rw.statusCodeSent)
			logger.WithError(err).Error("Failed to process request with Go-plugin middleware func")
		default:
			// record 2XX to analytics
			successHandler.RecordHit(r, analytics.Latency{Total: int64(ms)}, rw.statusCodeSent, rw.getHttpResponse(r), false)

			// no need to continue passing this request down to reverse proxy
			respCode = mwStatusRespond
		}
	} else {
		respCode = http.StatusOK
	}

	return
}

Cognitive complexity: 29, Cyclomatic complexity: 11

Uses: analytics.Latency, errors.New, fmt.Errorf, http.StatusBadRequest, http.StatusForbidden, http.StatusInternalServerError, http.StatusOK, http.StatusText, request.RealIP, time.Now, time.Since.

func (*GranularAccessMiddleware) Name

func (m *GranularAccessMiddleware) Name() string {
	return "GranularAccessMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GranularAccessMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (m *GranularAccessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	session := ctxGetSession(r)

	sessionVersionData, foundAPI := session.AccessRights[m.Spec.APIID]
	if !foundAPI {
		return nil, http.StatusOK
	}

	if len(sessionVersionData.AllowedURLs) == 0 {
		return nil, http.StatusOK
	}

	gwConfig := m.Gw.GetConfig()

	// Hook per-api settings here (m.Spec...)
	isPrefixMatch := gwConfig.HttpServerOptions.EnablePathPrefixMatching
	isSuffixMatch := gwConfig.HttpServerOptions.EnablePathSuffixMatching

	if isPrefixMatch {
		urlPaths := []string{
			m.Spec.StripListenPath(r.URL.Path),
			r.URL.Path,
		}

		logger := m.Logger().WithField("paths", urlPaths)

		for _, accessSpec := range sessionVersionData.AllowedURLs {
			if !slices.Contains(accessSpec.Methods, r.Method) {
				continue
			}

			// Append $ if so configured to match end of request path.
			pattern := httputil.PreparePathRegexp(accessSpec.URL, isPrefixMatch, isSuffixMatch)
			if isSuffixMatch && !strings.HasSuffix(pattern, "$") {
				pattern += "$"
			}

			match, err := httputil.MatchPaths(pattern, urlPaths)

			// unconditional log of err/match/url
			// if loglevel is set to debug verbosity increases and all requests are logged,
			// regardless if an error occured or not.
			if gwConfig.LogLevel == "debug" || err != nil {
				logger = logger.WithError(err).WithField("pattern", pattern).WithField("match", match)
				if err != nil {
					logger.Error("error matching endpoint")
				} else {
					logger.Debug("matching endpoint")
				}
			}

			if err != nil || !match {
				continue
			}
			return m.pass()
		}

		return m.block(logger)
	}

	logger := m.Logger().WithField("paths", []string{r.URL.Path})

	// Legacy behaviour (5.5.0 and earlier), wildcard match against full request path.
	// Fixed error handling in regex compilation to continue to next pattern (block).
	urlPath := r.URL.Path

	for _, accessSpec := range sessionVersionData.AllowedURLs {
		if !slices.Contains(accessSpec.Methods, r.Method) {
			continue
		}

		pattern := httputil.PreparePathRegexp(accessSpec.URL, false, isSuffixMatch)

		logger.Debug("Checking: ", urlPath, " Against:", pattern)

		// Wildcard match (user supplied, as-is)
		asRegex, err := regexp.Compile(pattern)
		if err != nil {
			logger.WithError(err).Error("error compiling regex")
			continue
		}

		match := asRegex.MatchString(r.URL.Path)
		if match {
			return m.pass()
		}
	}

	return m.block(logger)
}

Cognitive complexity: 35, Cyclomatic complexity: 18

Uses: http.StatusOK, httputil.MatchPaths, httputil.PreparePathRegexp, regexp.Compile, slices.Contains, strings.HasSuffix.

func (*GraphQLComplexityMiddleware) EnabledForSpec

func (m *GraphQLComplexityMiddleware) EnabledForSpec() bool {
	return m.Spec.GraphQL.Enabled
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GraphQLComplexityMiddleware) Name

func (m *GraphQLComplexityMiddleware) Name() string {
	return "GraphQLComplexityMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GraphQLComplexityMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (m *GraphQLComplexityMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	accessDef, _, err := GetAccessDefinitionByAPIIDOrSession(ctxGetSession(r), m.Spec)
	if err != nil {
		m.Logger().Debugf("Error while calculating GraphQL complexity: '%s'", err)
		return m.handleComplexityFailReason(ComplexityFailReasonInternalError)
	}

	graphEngineComplexityAccessDefinition := &graphengine.ComplexityAccessDefinition{
		Limit: graphengine.ComplexityLimit{
			MaxQueryDepth: accessDef.Limit.MaxQueryDepth,
		},
		FieldAccessRights:	[]graphengine.ComplexityFieldAccessDefinition{},
	}

	for _, fieldAccessRight := range accessDef.FieldAccessRights {
		graphEngineComplexityAccessDefinition.FieldAccessRights = append(graphEngineComplexityAccessDefinition.FieldAccessRights, graphengine.ComplexityFieldAccessDefinition{
			TypeName:	fieldAccessRight.TypeName,
			FieldName:	fieldAccessRight.FieldName,
			Limits: graphengine.ComplexityFieldLimits{
				MaxQueryDepth: fieldAccessRight.Limits.MaxQueryDepth,
			},
		})
	}

	return m.Spec.GraphEngine.ProcessGraphQLComplexity(r, graphEngineComplexityAccessDefinition)
}

Cognitive complexity: 11, Cyclomatic complexity: 3

Uses: graphengine.ComplexityAccessDefinition, graphengine.ComplexityFieldAccessDefinition, graphengine.ComplexityFieldLimits, graphengine.ComplexityLimit.

func (*GraphQLGranularAccessMiddleware) EnabledForSpec

func (m *GraphQLGranularAccessMiddleware) EnabledForSpec() bool {
	return m.Spec.GraphQL.Enabled
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GraphQLGranularAccessMiddleware) Name

func (m *GraphQLGranularAccessMiddleware) Name() string {
	return "GraphQLGranularAccessMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GraphQLGranularAccessMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (m *GraphQLGranularAccessMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	session := ctxGetSession(r)

	accessDef, foundAPI := session.AccessRights[m.Spec.APIID]
	if !foundAPI {
		return nil, http.StatusOK
	}

	graphEngineGranularAccessDefinition := &graphengine.GranularAccessDefinition{
		AllowedTypes:		make([]graphengine.GranularAccessType, 0),
		RestrictedTypes:	make([]graphengine.GranularAccessType, 0),
		DisableIntrospection:	accessDef.DisableIntrospection,
	}

	for _, allowedType := range accessDef.AllowedTypes {
		graphEngineGranularAccessDefinition.AllowedTypes = append(graphEngineGranularAccessDefinition.AllowedTypes, graphengine.GranularAccessType{
			Name:	allowedType.Name,
			Fields:	allowedType.Fields,
		})
	}
	for _, restrictedType := range accessDef.RestrictedTypes {
		graphEngineGranularAccessDefinition.RestrictedTypes = append(graphEngineGranularAccessDefinition.RestrictedTypes, graphengine.GranularAccessType{
			Name:	restrictedType.Name,
			Fields:	restrictedType.Fields,
		})
	}

	return m.Spec.GraphEngine.ProcessGraphQLGranularAccess(w, r, graphEngineGranularAccessDefinition)
}

Cognitive complexity: 14, Cyclomatic complexity: 5

Uses: graphengine.GranularAccessDefinition, graphengine.GranularAccessType, http.StatusOK.

func (*GraphQLMiddleware) EnabledForSpec

func (m *GraphQLMiddleware) EnabledForSpec() bool {
	return m.Spec.GraphQL.Enabled
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GraphQLMiddleware) Init

func (m *GraphQLMiddleware) Init() {
	schema, err := gql.NewSchemaFromString(m.Spec.GraphQL.Schema)
	if err != nil {
		log.Errorf("Error while creating schema from API definition: %v", err)
		return
	}

	normalizationResult, err := schema.Normalize()
	if err != nil {
		log.Errorf("Error while normalizing schema from API definition: %v", err)
	}

	if !normalizationResult.Successful {
		log.Errorf("Schema normalization was not successful. Reason: %v", normalizationResult.Errors)
	}

	reusableBodyReadCloser := func(buf io.ReadCloser) (io.ReadCloser, error) {
		return newNopCloserBuffer(buf)
	}

	if m.Spec.GraphQL.Version == apidef.GraphQLConfigVersionNone || m.Spec.GraphQL.Version == apidef.GraphQLConfigVersion1 {
		if m.Spec.GraphQL.Version == apidef.GraphQLConfigVersionNone {
			log.Warn("GraphQL config version is not set, defaulting to version 1")
		}

		log.Info("GraphQL Config Version 1 is deprecated - Please consider migrating to version 2 or higher")
		m.Spec.GraphEngine, err = graphengine.NewEngineV1(graphengine.EngineV1Options{
			Logger:		log,
			ApiDefinition:	m.Spec.APIDefinition,
			Schema:		schema,
			HttpClient: &http.Client{
				Transport: &http.Transport{TLSClientConfig: tlsClientConfig(m.Spec, nil)},
			},
			Injections: graphengine.EngineV1Injections{
				PreSendHttpHook:		preSendHttpHook{m},
				PostReceiveHttpHook:		postReceiveHttpHook{m},
				ContextStoreRequest:		ctxSetGraphQLRequest,
				ContextRetrieveRequest:		ctxGetGraphQLRequest,
				NewReusableBodyReadCloser:	reusableBodyReadCloser,
			},
		})
	} else if m.Spec.GraphQL.Version == apidef.GraphQLConfigVersion2 {
		httpClient := &http.Client{
			Transport: &http.Transport{TLSClientConfig: tlsClientConfig(m.Spec, nil)},
		}
		m.Spec.GraphEngine, err = graphengine.NewEngineV2(graphengine.EngineV2Options{
			Logger:			log,
			Schema:			schema,
			ApiDefinition:		m.Spec.APIDefinition,
			HttpClient:		httpClient,
			StreamingClient:	httpClient,
			OpenTelemetry: graphengine.EngineV2OTelConfig{
				Enabled:	m.Gw.GetConfig().OpenTelemetry.Enabled,
				TracerProvider:	m.Gw.TracerProvider,
			},
			Injections: graphengine.EngineV2Injections{
				BeforeFetchHook:		m,
				AfterFetchHook:			m,
				WebsocketOnBeforeStart:		m,
				ContextStoreRequest:		ctxSetGraphQLRequest,
				ContextRetrieveRequest:		ctxGetGraphQLRequest,
				NewReusableBodyReadCloser:	reusableBodyReadCloser,
				SeekReadCloser: func(readCloser io.ReadCloser) (io.ReadCloser, error) {
					body, ok := readCloser.(*nopCloserBuffer)
					if !ok {
						return nil, nil
					}
					_, err := body.Seek(0, io.SeekStart)
					if err != nil {
						return nil, err
					}
					return body, nil
				},
				TykVariableReplacer:	m.Gw.ReplaceTykVariables,
			},
		})
	} else if m.Spec.GraphQL.Version == apidef.GraphQLConfigVersion3Preview {
		v2Schema, err := gqlv2.NewSchemaFromString(m.Spec.GraphQL.Schema)
		if err != nil {
			log.Errorf("Error while creating schema from API definition: %v", err)
			return
		}
		engine, err := graphengine.NewEngineV3(graphengine.EngineV3Options{
			Logger:		log,
			Schema:		v2Schema,
			ApiDefinition:	m.Spec.APIDefinition,
			OpenTelemetry: graphengine.EngineV2OTelConfig{
				Enabled:	m.Gw.GetConfig().OpenTelemetry.Enabled,
				TracerProvider:	m.Gw.TracerProvider,
			},
			HttpClient: &http.Client{
				Transport: &http.Transport{TLSClientConfig: tlsClientConfig(m.Spec, nil)},
			},
			Injections: graphengine.EngineV3Injections{
				ContextRetrieveRequest:	ctxGetGraphQLRequestV2,
				ContextStoreRequest:	ctxSetGraphQLRequestV2,
				// TODO use proper version or request for this
				//WebsocketOnBeforeStart:    m,
				NewReusableBodyReadCloser:	reusableBodyReadCloser,
				SeekReadCloser: func(readCloser io.ReadCloser) (io.ReadCloser, error) {
					body, ok := readCloser.(*nopCloserBuffer)
					if !ok {
						return nil, nil
					}
					_, err := body.Seek(0, io.SeekStart)
					if err != nil {
						return nil, err
					}
					return body, nil
				},
				TykVariableReplacer:	m.Gw.ReplaceTykVariables,
			},
		})
		if err != nil {
			log.Errorf("Error creating enginev3: %v", err)
			return
		}
		m.Spec.GraphEngine = engine
	} else {
		log.Errorf("Could not init GraphQL middleware: invalid config version provided: %s", m.Spec.GraphQL.Version)
	}
}

Cognitive complexity: 47, Cyclomatic complexity: 15

Uses: apidef.GraphQLConfigVersion1, apidef.GraphQLConfigVersion2, apidef.GraphQLConfigVersion3Preview, apidef.GraphQLConfigVersionNone, gql.NewSchemaFromString, gqlv2.NewSchemaFromString, graphengine.EngineV1Injections, graphengine.EngineV1Options, graphengine.EngineV2Injections, graphengine.EngineV2OTelConfig, graphengine.EngineV2Options, graphengine.EngineV3Injections, graphengine.EngineV3Options, graphengine.NewEngineV1, graphengine.NewEngineV2, graphengine.NewEngineV3, http.Client, http.Transport, io.ReadCloser, io.SeekStart.

func (*GraphQLMiddleware) Name

func (m *GraphQLMiddleware) Name() string {
	return "GraphQLMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*GraphQLMiddleware) OnBeforeFetch

func (m *GraphQLMiddleware) OnBeforeFetch(ctx resolve.HookContext, input []byte) {
	m.BaseMiddleware.Logger().
		WithFields(
			logrus.Fields{
				"path": ctx.CurrentPath,
			},
		).Debugf("%s (beforeFetchHook): %s", ctx.CurrentPath, string(input))
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: logrus.Fields.

func (*GraphQLMiddleware) OnBeforeStart

OnBeforeStart - is a graphql.WebsocketBeforeStartHook which allows to perform security checks for all operations over websocket connections

func (m *GraphQLMiddleware) OnBeforeStart(reqCtx context.Context, operation *gql.Request) error {
	if m.Spec.UseKeylessAccess {
		return nil
	}

	schema, err := graphengine.GetSchemaV1(m.Spec.GraphEngine)
	if err != nil {
		return err
	}

	v := reqCtx.Value(ctx.SessionData)
	if v == nil {
		m.Logger().Error("failed to get session in OnBeforeStart hook")
		return errors.New("empty session")
	}
	session := v.(*user.SessionState)

	accessDef, _, err := GetAccessDefinitionByAPIIDOrSession(session, m.Spec)
	if err != nil {
		m.Logger().Errorf("failed to get access definition in OnBeforeStart hook: '%s'", err)
		return err
	}

	complexityCheck := &GraphqlComplexityChecker{logger: m.Logger()}
	depthResult := complexityCheck.DepthLimitExceeded(operation, accessDef, schema)
	switch depthResult {
	case ComplexityFailReasonInternalError:
		return ProxyingRequestFailedErr
	case ComplexityFailReasonDepthLimitExceeded:
		return GraphQLDepthLimitExceededErr
	}

	granularAccessCheck := &GraphqlGranularAccessChecker{}
	result := granularAccessCheck.CheckGraphqlRequestFieldAllowance(operation, accessDef, schema)
	switch result.failReason {
	case GranularAccessFailReasonInternalError:
		m.Logger().Errorf(RestrictedFieldValidationFailedLogMsg, result.internalErr)
		return ProxyingRequestFailedErr
	case GranularAccessFailReasonValidationError:
		m.Logger().Debugf(RestrictedFieldValidationFailedLogMsg, result.validationResult.Errors)
		return result.validationResult.Errors
	}

	return nil
}

Cognitive complexity: 18, Cyclomatic complexity: 11

Uses: ctx.SessionData, errors.New, graphengine.GetSchemaV1, user.SessionState.

func (*GraphQLMiddleware) OnData

func (m *GraphQLMiddleware) OnData(ctx resolve.HookContext, output []byte, singleFlight bool) {
	m.BaseMiddleware.Logger().
		WithFields(
			logrus.Fields{
				"path":			ctx.CurrentPath,
				"single_flight":	singleFlight,
			},
		).Debugf("%s (afterFetchHook.OnData): %s", ctx.CurrentPath, string(output))
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: logrus.Fields.

func (*GraphQLMiddleware) OnError

func (m *GraphQLMiddleware) OnError(ctx resolve.HookContext, output []byte, singleFlight bool) {
	m.BaseMiddleware.Logger().
		WithFields(
			logrus.Fields{
				"path":			ctx.CurrentPath,
				"single_flight":	singleFlight,
			},
		).Debugf("%s (afterFetchHook.OnError): %s", ctx.CurrentPath, string(output))
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: logrus.Fields.

func (*GraphQLMiddleware) ProcessRequest

func (m *GraphQLMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	err := m.checkForUnsupportedUsage()
	if err != nil {
		m.Logger().WithError(err).Error("request could not be executed because of unsupported usage")
		return ProxyingRequestFailedErr, http.StatusInternalServerError
	}

	if m.Spec.GraphEngine == nil {
		m.Logger().Error("GraphEngine is not initialized")
		return ProxyingRequestFailedErr, http.StatusInternalServerError
	}

	if !m.Spec.GraphEngine.HasSchema() {
		m.Logger().Error("Schema is not created")
		return ProxyingRequestFailedErr, http.StatusInternalServerError
	}

	if websocket.IsWebSocketUpgrade(r) {
		if !m.websocketUpgradeAllowed() {
			return errors.New("websockets are not allowed"), http.StatusUnprocessableEntity
		}

		if !m.websocketUpgradeUsesGraphQLProtocol(r) {
			return errors.New("invalid websocket protocol for upgrading to a graphql websocket connection"), http.StatusBadRequest
		}

		ctxSetGraphQLIsWebSocketUpgrade(r, true)
		return nil, http.StatusSwitchingProtocols
	}

	// With current in memory server approach we need body to be readable again
	// as for proxy only API we are sending it as is
	nopCloseRequestBody(r)

	return m.Spec.GraphEngine.ProcessAndStoreGraphQLRequest(w, r)
}

Cognitive complexity: 13, Cyclomatic complexity: 7

Uses: errors.New, http.StatusBadRequest, http.StatusInternalServerError, http.StatusSwitchingProtocols, http.StatusUnprocessableEntity, websocket.IsWebSocketUpgrade.

func (*GraphqlComplexityChecker) DepthLimitEnabled

func (c *GraphqlComplexityChecker) DepthLimitEnabled(accessDef *user.AccessDefinition) bool {
	// There is a possibility that depth limit is disabled on field level too,
	// but we could not determine this without analyzing actual requested fields.
	if len(accessDef.FieldAccessRights) > 0 {
		return true
	}

	// If MaxQueryDepth is -1 or 0, it means unlimited and no need for depth limiting.
	return accessDef.Limit.MaxQueryDepth > 0
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*GraphqlComplexityChecker) DepthLimitExceeded

func (c *GraphqlComplexityChecker) DepthLimitExceeded(gqlRequest *graphql.Request, accessDef *user.AccessDefinition, schema *graphql.Schema) ComplexityFailReason {
	if !c.DepthLimitEnabled(accessDef) {
		return ComplexityFailReasonNone
	}

	isIntrospectionQuery, err := gqlRequest.IsIntrospectionQuery()
	if err != nil {
		c.logger.Debugf("Error while checking for introspection query: '%s'", err.Error())
		return ComplexityFailReasonInternalError
	}

	if isIntrospectionQuery {
		return ComplexityFailReasonNone
	}

	complexityRes, err := gqlRequest.CalculateComplexity(graphql.DefaultComplexityCalculator, schema)
	if err != nil {
		c.logger.Errorf("Error while calculating complexity of GraphQL request: '%s'", err)
		return ComplexityFailReasonInternalError
	}

	if complexityRes.Errors != nil && complexityRes.Errors.Count() > 0 {
		c.logger.Errorf("Error while calculating complexity of GraphQL request: '%s'", complexityRes.Errors.ErrorByIndex(0))
		return ComplexityFailReasonInternalError
	}

	// do per query depth check
	if len(accessDef.FieldAccessRights) == 0 {
		if complexityRes.Depth > accessDef.Limit.MaxQueryDepth {
			c.logger.Debugf("Complexity of the request is higher than the allowed limit '%d'", accessDef.Limit.MaxQueryDepth)
			return ComplexityFailReasonDepthLimitExceeded
		}
		return ComplexityFailReasonNone
	}

	// do per query field depth check
	for _, fieldComplexityRes := range complexityRes.PerRootField {
		var (
			fieldAccessDefinition	user.FieldAccessDefinition
			hasPerFieldLimits	bool
		)

		for _, fieldAccessRight := range accessDef.FieldAccessRights {
			if fieldComplexityRes.TypeName != fieldAccessRight.TypeName {
				continue
			}
			if fieldComplexityRes.FieldName != fieldAccessRight.FieldName {
				continue
			}

			fieldAccessDefinition = fieldAccessRight
			hasPerFieldLimits = true
			break
		}

		if hasPerFieldLimits {
			if greaterThanInt(fieldComplexityRes.Depth, fieldAccessDefinition.Limits.MaxQueryDepth) {
				c.logger.Debugf("Depth '%d' of the root field: %s.%s is higher than the allowed field limit '%d'",
					fieldComplexityRes.Depth, fieldAccessDefinition.TypeName, fieldAccessDefinition.FieldName, fieldAccessDefinition.Limits.MaxQueryDepth)

				return ComplexityFailReasonDepthLimitExceeded
			}
			continue
		}

		// favour global limit for query field
		// have to increase resulting field depth by 1 to get a global depth
		queryDepth := fieldComplexityRes.Depth + 1
		if greaterThanInt(queryDepth, accessDef.Limit.MaxQueryDepth) {
			c.logger.Debugf("Depth '%d' of the root field: %s.%s is higher than the allowed global limit '%d'",
				queryDepth, fieldComplexityRes.TypeName, fieldComplexityRes.FieldName, accessDef.Limit.MaxQueryDepth)

			return ComplexityFailReasonDepthLimitExceeded
		}
	}
	return ComplexityFailReasonNone
}

Cognitive complexity: 30, Cyclomatic complexity: 16

Uses: graphql.DefaultComplexityCalculator, user.FieldAccessDefinition.

func (*GraphqlGranularAccessChecker) CheckGraphqlRequestFieldAllowance

func (g *GraphqlGranularAccessChecker) CheckGraphqlRequestFieldAllowance(gqlRequest *graphql.Request, accessDef *user.AccessDefinition, schema *graphql.Schema) GraphqlGranularAccessResult {
	if len(accessDef.AllowedTypes) != 0 {
		fieldRestrictionList := graphql.FieldRestrictionList{
			Kind:	graphql.AllowList,
			Types:	accessDef.AllowedTypes,
		}
		return g.validateFieldRestrictions(gqlRequest, fieldRestrictionList, schema)
	}

	if len(accessDef.RestrictedTypes) != 0 {
		fieldRestrictionList := graphql.FieldRestrictionList{
			Kind:	graphql.BlockList,
			Types:	accessDef.RestrictedTypes,
		}
		return g.validateFieldRestrictions(gqlRequest, fieldRestrictionList, schema)
	}

	// There are no restricted types. Every field is allowed access.
	return GraphqlGranularAccessResult{failReason: GranularAccessFailReasonNone}
}

Cognitive complexity: 7, Cyclomatic complexity: 3

Uses: graphql.AllowList, graphql.BlockList, graphql.FieldRestrictionList.

func (*HTTPBundleGetter) Get

Get performs an HTTP GET request.

func (g *HTTPBundleGetter) Get() ([]byte, error) {
	tr := &(*http.DefaultTransport.(*http.Transport))
	tr.TLSClientConfig = &tls.Config{
		InsecureSkipVerify:	g.InsecureSkipVerify,
		MaxVersion:		tls.VersionTLS12,
	}
	client := &http.Client{Transport: tr}
	client.Timeout = 5 * time.Second

	log.Infof("Attempting to download plugin bundle: %v", g.URL)
	resp, err := client.Get(g.URL)
	if err != nil {
		return nil, fmt.Errorf("Error getting bundle: %w", err)
	}

	if resp.StatusCode != 200 {
		httpError := fmt.Sprintf("HTTP Error, got status code %d", resp.StatusCode)
		return nil, errors.New(httpError)
	}

	defer resp.Body.Close()
	return ioutil.ReadAll(resp.Body)
}

Cognitive complexity: 6, Cyclomatic complexity: 3

Uses: errors.New, fmt.Errorf, fmt.Sprintf, http.Client, http.DefaultTransport, http.Transport, ioutil.ReadAll, time.Second, tls.Config, tls.VersionTLS12.

func (*HTTPDashboardHandler) DeRegister

func (h *HTTPDashboardHandler) DeRegister() error {
	req := h.newRequest(http.MethodDelete, h.DeRegistrationEndpoint)

	req.Header.Set(header.XTykNodeID, h.Gw.GetNodeID())
	h.Gw.ServiceNonceMutex.RLock()
	req.Header.Set(header.XTykNonce, h.Gw.ServiceNonce)
	h.Gw.ServiceNonceMutex.RUnlock()

	c := h.Gw.initialiseClient()
	resp, err := c.Do(req)

	if err != nil {
		return fmt.Errorf("deregister request failed with error %w", err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("deregister request failed with status %d", resp.StatusCode)
	}

	val := NodeResponseOK{}
	if err := json.NewDecoder(resp.Body).Decode(&val); err != nil {
		return err
	}

	// Set the nonce
	h.Gw.ServiceNonceMutex.Lock()
	h.Gw.ServiceNonce = val.Nonce
	h.Gw.ServiceNonceMutex.Unlock()
	dashLog.Info("De-registered.")

	return nil
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: fmt.Errorf, header.XTykNodeID, header.XTykNonce, http.MethodDelete, http.StatusOK, json.NewDecoder.

func (*HTTPDashboardHandler) Init

func (h *HTTPDashboardHandler) Init() error {
	h.RegistrationEndpoint = h.Gw.buildDashboardConnStr("/register/node")
	h.DeRegistrationEndpoint = h.Gw.buildDashboardConnStr("/system/node")
	h.HeartBeatEndpoint = h.Gw.buildDashboardConnStr("/register/ping")
	h.KeyQuotaTriggerEndpoint = h.Gw.buildDashboardConnStr("/system/key/quota_trigger")

	if h.Secret = h.Gw.GetConfig().NodeSecret; h.Secret == "" {
		dashLog.Fatal("Node secret is not set, required for dashboard connection")
	}
	return nil
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*HTTPDashboardHandler) NotifyDashboardOfEvent

NotifyDashboardOfEvent acts as a form of event which informs the dashboard of a key which has reached a certain usage quota

func (h *HTTPDashboardHandler) NotifyDashboardOfEvent(event interface{}) error {

	meta, ok := event.(EventTriggerExceededMeta)
	if !ok {
		return errors.New("event type is currently not supported as a notification to the dashboard")
	}

	var b bytes.Buffer
	if err := json.NewEncoder(&b).Encode(meta); err != nil {
		log.Errorf("Could not decode event metadata :%v", err)
		return err
	}

	req, err := http.NewRequest(http.MethodPost, h.KeyQuotaTriggerEndpoint, &b)
	if err != nil {
		log.Errorf("Could not create request.. %v", err)
		return err
	}

	req.Header.Set("authorization", h.Secret)
	req.Header.Set(header.XTykNodeID, h.Gw.GetNodeID())
	h.Gw.ServiceNonceMutex.RLock()
	req.Header.Set(header.XTykNonce, h.Gw.ServiceNonce)
	h.Gw.ServiceNonceMutex.RUnlock()

	c := h.Gw.initialiseClient()

	resp, err := c.Do(req)
	if err != nil {
		log.Errorf("Request failed with error %v", err)
		return err
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		err := fmt.Errorf("unexpected status code while trying to notify dashboard of a key limit quota trigger.. Got %d", resp.StatusCode)
		log.Error(err)
		return err
	}

	val := NodeResponseOK{}
	if err := json.NewDecoder(resp.Body).Decode(&val); err != nil {
		return err
	}

	h.Gw.ServiceNonceMutex.Lock()
	h.Gw.ServiceNonce = val.Nonce
	h.Gw.ServiceNonceMutex.Unlock()

	return nil
}

Cognitive complexity: 14, Cyclomatic complexity: 7

Uses: bytes.Buffer, errors.New, fmt.Errorf, header.XTykNodeID, header.XTykNonce, http.MethodPost, http.NewRequest, http.StatusOK, json.NewDecoder, json.NewEncoder.

func (*HTTPDashboardHandler) Ping

func (h *HTTPDashboardHandler) Ping() error {
	return h.sendHeartBeat(
		h.newRequest(http.MethodGet, h.HeartBeatEndpoint),
		h.Gw.initialiseClient())
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: http.MethodGet.

func (*HTTPDashboardHandler) Register

func (h *HTTPDashboardHandler) Register() error {
	dashLog.Info("Registering gateway node with Dashboard")
	req := h.newRequest(http.MethodGet, h.RegistrationEndpoint)
	req.Header.Set(header.XTykSessionID, h.Gw.SessionID)

	c := h.Gw.initialiseClient()

	resp, err := c.Do(req)

	if err != nil {
		dashLog.Errorf("Request failed with error %v; retrying in 5s", err)
		time.Sleep(time.Second * 5)
		return h.Register()
	} else if resp.StatusCode == http.StatusConflict {
		dashLog.Debug("Node is already registered")
		return nil
	} else if resp != nil && resp.StatusCode != 200 {
		dashLog.Errorf("Response failed with code %d; retrying in 5s", resp.StatusCode)
		time.Sleep(time.Second * 5)
		return h.Register()
	}

	defer resp.Body.Close()
	val := NodeResponseOK{}
	if err := json.NewDecoder(resp.Body).Decode(&val); err != nil {
		return err
	}

	// Set the NodeID
	var found bool
	nodeID, found := val.Message["NodeID"]
	h.Gw.SetNodeID(nodeID)
	if !found {
		dashLog.Error("Failed to register node, retrying in 5s")
		time.Sleep(time.Second * 5)
		return h.Register()
	}

	dashLog.WithField("id", h.Gw.GetNodeID()).Info("Node Registered")

	// Set the nonce
	h.Gw.ServiceNonceMutex.Lock()
	h.Gw.ServiceNonce = val.Nonce
	h.Gw.ServiceNonceMutex.Unlock()
	dashLog.Debug("Registration Finished: Nonce Set: ", val.Nonce)
	h.Gw.DoReload()

	return nil
}

Cognitive complexity: 11, Cyclomatic complexity: 7

Uses: header.XTykSessionID, http.MethodGet, http.StatusConflict, json.NewDecoder, time.Second, time.Sleep.

func (*HTTPDashboardHandler) StartBeating

func (h *HTTPDashboardHandler) StartBeating() error {
	atomic.SwapInt32(&h.heartBeatStopSentinel, HeartBeatStarted)

	req := h.newRequest(http.MethodGet, h.HeartBeatEndpoint)

	client := h.Gw.initialiseClient()

	for !h.isHeartBeatStopped() {
		if err := h.sendHeartBeat(req, client); err != nil {
			dashLog.Warning(err)
		}
		time.Sleep(time.Second * 2)
	}

	dashLog.Info("Stopped Heartbeat")
	return nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: atomic.SwapInt32, http.MethodGet, time.Second, time.Sleep.

func (*HTTPDashboardHandler) StopBeating

func (h *HTTPDashboardHandler) StopBeating() {
	atomic.SwapInt32(&h.heartBeatStopSentinel, HeartBeatStopped)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: atomic.SwapInt32.

func (*HTTPSignatureValidationMiddleware) EnabledForSpec

func (k *HTTPSignatureValidationMiddleware) EnabledForSpec() bool {
	return k.Spec.EnableSignatureChecking
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HTTPSignatureValidationMiddleware) Init

func (hm *HTTPSignatureValidationMiddleware) Init() {
	hm.lowercasePattern = regexp.MustCompile(`%[a-f0-9][a-f0-9]`)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: regexp.MustCompile.

func (*HTTPSignatureValidationMiddleware) Name

func (hm *HTTPSignatureValidationMiddleware) Name() string {
	return "HTTPSignatureValidationMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HTTPSignatureValidationMiddleware) ProcessRequest

func (hm *HTTPSignatureValidationMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	token, _ := hm.getAuthToken(hm.getAuthType(), r)
	if token == "" {
		return hm.authorizationError(r)
	}
	logger := hm.Logger().WithField("key", hm.Gw.obfuscateKey(token))

	// Clean it
	token = stripSignature(token)

	// Separate out the field values
	fieldValues, err := getFieldValues(token)
	if err != nil {
		logger.WithError(err).Error("Field extraction failed")
		return hm.authorizationError(r)
	}

	// Generate a signature string
	signatureString, err := generateHMACSignatureStringFromRequest(r, fieldValues.Headers, r.URL.Path)

	if err != nil {
		logger.WithError(err).WithField("signature_string", signatureString).Error("Signature string generation failed")
		return hm.authorizationError(r)
	}

	if len(hm.Spec.HmacAllowedAlgorithms) > 0 {
		algorithmAllowed := false
		for _, alg := range hm.Spec.HmacAllowedAlgorithms {
			if alg == fieldValues.Algorthm {
				algorithmAllowed = true
				break
			}
		}
		if !algorithmAllowed {
			logger.WithError(err).WithField("algorithm", fieldValues.Algorthm).Error("Algorithm not supported")
			return hm.authorizationError(r)
		}
	}

	var secret string
	var rsaKey *rsa.PublicKey
	var session user.SessionState

	if strings.HasPrefix(fieldValues.Algorthm, "rsa") {
		var certificateId string

		certificateId, session, err = hm.getRSACertificateIdAndSessionForKeyID(r, fieldValues.KeyID)
		if err != nil {
			logger.WithError(err).WithFields(logrus.Fields{
				"keyID": fieldValues.KeyID,
			}).Error("Failed to fetch session/public key")
			return hm.authorizationError(r)
		}

		publicKey := hm.Gw.CertificateManager.ListRawPublicKey(certificateId)
		if publicKey == nil {
			log.Error("Certificate not found")
			return errors.New("Certificate not found"), http.StatusInternalServerError
		}
		var ok bool
		rsaKey, ok = publicKey.(*rsa.PublicKey)
		if !ok {
			log.Error("Certificate doesn't contain RSA Public key")
			return errors.New("Certificate doesn't contain RSA Public key"), http.StatusInternalServerError
		}
	} else {
		// Get a session for the Key ID
		secret, session, err = hm.getSecretAndSessionForKeyID(r, fieldValues.KeyID)
		if err != nil {
			logger.WithError(err).WithFields(logrus.Fields{
				"keyID": fieldValues.KeyID,
			}).Error("No HMAC secret for this key")
			return hm.authorizationError(r)
		}
	}
	var matchPass bool

	if strings.HasPrefix(fieldValues.Algorthm, "rsa") {
		matchPass, err = validateRSAEncodedSignature(signatureString, rsaKey, fieldValues.Algorthm, fieldValues.Signature)
		if err != nil {
			logger.WithError(err).Error("Signature validation failed.")
		}

		if !matchPass {
			isLower, lowerList := hm.hasLowerCaseEscaped(fieldValues.Signature)
			if isLower {
				logger.Debug("--- Detected lower case encoding! ---")
				upperedSignature := hm.replaceWithUpperCase(fieldValues.Signature, lowerList)
				matchPass, err = validateRSAEncodedSignature(signatureString, rsaKey, fieldValues.Algorthm, upperedSignature)
				if err != nil {
					logger.WithError(err).Error("Signature validation failed.")
				}
			}
		}

		if !matchPass {
			logger.WithFields(logrus.Fields{
				"got": fieldValues.Signature,
			}).Error("Signature string does not match!")
			return hm.authorizationError(r)
		}
	} else {
		// Create a signed string with the secret
		encodedSignature, err := generateHMACEncodedSignature(signatureString, secret, fieldValues.Algorthm)
		if err != nil {
			logger.WithFields(logrus.Fields{
				"error": err,
			}).Error("Failed to validate signature")
			return hm.authorizationError(r)
		}

		// Compare
		matchPass = encodedSignature == fieldValues.Signature

		// Check for lower case encoding (.Net issues, again)
		if !matchPass {
			isLower, lowerList := hm.hasLowerCaseEscaped(fieldValues.Signature)
			if isLower {
				logger.Debug("--- Detected lower case encoding! ---")
				upperedSignature := hm.replaceWithUpperCase(fieldValues.Signature, lowerList)
				if encodedSignature == upperedSignature {
					matchPass = true
					encodedSignature = upperedSignature
				}
			}
		}

		if !matchPass {
			logger.WithFields(logrus.Fields{
				"got": fieldValues.Signature,
			}).Error("Signature string does not match!")
			return hm.authorizationError(r)
		}
	}

	// Check clock skew
	_, dateVal := getDateHeader(r)
	if !hm.checkClockSkew(dateVal) {
		logger.Error("Clock skew outside of acceptable bounds")
		return hm.authorizationError(r)
	}

	// Set session state on context, we will need it later
	switch hm.Spec.BaseIdentityProvidedBy {
	case apidef.HMACKey, apidef.UnsetAuth:
		session.KeyID = fieldValues.KeyID
		ctxSetSession(r, &session, false, hm.Gw.GetConfig().HashKeys)
		hm.setContextVars(r, fieldValues.KeyID)
	}

	// Everything seems in order let the request through
	return nil, http.StatusOK
}

Cognitive complexity: 64, Cyclomatic complexity: 28

Uses: apidef.HMACKey, apidef.UnsetAuth, errors.New, http.StatusInternalServerError, http.StatusOK, logrus.Fields, rsa.PublicKey, strings.HasPrefix, user.SessionState.

func (*HeaderInjector) Base

func (h *HeaderInjector) Base() *BaseTykResponseHandler {
	return &h.BaseTykResponseHandler
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HeaderInjector) Enabled

func (h *HeaderInjector) Enabled() bool {
	for _, version := range h.Spec.VersionData.Versions {
		if version.GlobalResponseHeadersEnabled() {
			return true
		}

		if version.HasEndpointResHeader() {
			return true
		}
	}

	return false
}

Cognitive complexity: 7, Cyclomatic complexity: 4

func (*HeaderInjector) HandleError

func (h *HeaderInjector) HandleError(rw http.ResponseWriter, req *http.Request) {
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HeaderInjector) HandleResponse

func (h *HeaderInjector) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error {
	// TODO: This should only target specific paths
	ignoreCanonical := h.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
	vInfo, _ := h.Spec.Version(req)
	versionPaths := h.Spec.RxPaths[vInfo.Name]

	found, meta := h.Spec.CheckSpecMatchesStatus(req, versionPaths, HeaderInjectedResponse)
	if found {
		hmeta := meta.(*apidef.HeaderInjectionMeta)
		for _, dKey := range hmeta.DeleteHeaders {
			res.Header.Del(dKey)
		}
		for nKey, nVal := range hmeta.AddHeaders {
			setCustomHeader(res.Header, nKey, h.Gw.ReplaceTykVariables(req, nVal, false), ignoreCanonical)
		}
	}

	// Manage global response header options with versionInfo
	if !vInfo.GlobalResponseHeadersDisabled {
		for _, key := range vInfo.GlobalResponseHeadersRemove {
			log.Debug("Removing: ", key)
			res.Header.Del(key)
		}

		for key, val := range vInfo.GlobalResponseHeaders {
			log.Debug("Adding: ", key)
			setCustomHeader(res.Header, key, h.Gw.ReplaceTykVariables(req, val, false), ignoreCanonical)
		}

		// Manage global response header options with response_processors
		for _, n := range h.config.RemoveHeaders {
			res.Header.Del(n)
		}
		for header, v := range h.config.AddHeaders {
			setCustomHeader(res.Header, header, h.Gw.ReplaceTykVariables(req, v, false), ignoreCanonical)
		}
	}

	return nil
}

Cognitive complexity: 22, Cyclomatic complexity: 9

Uses: apidef.HeaderInjectionMeta.

func (*HeaderInjector) Init

func (h *HeaderInjector) Init(c interface{}, spec *APISpec) error {
	h.Spec = spec
	return mapstructure.Decode(c, &h.config)
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: mapstructure.Decode.

func (*HeaderInjector) Name

func (*HeaderInjector) Name() string {
	return "HeaderInjector"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HeaderTransform) Base

func (h *HeaderTransform) Base() *BaseTykResponseHandler {
	return &h.BaseTykResponseHandler
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HeaderTransform) HandleError

func (h *HeaderTransform) HandleError(rw http.ResponseWriter, req *http.Request) {
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HeaderTransform) HandleResponse

func (h *HeaderTransform) HandleResponse(rw http.ResponseWriter,
	res *http.Response, req *http.Request, ses *user.SessionState) error {

	// Parse target_host parameter from configuration
	target_url, err := url.Parse(h.config.RevProxyTransform.Target_host)
	if err != nil {
		return err
	}
	ignoreCanonical := h.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
	for _, name := range h.config.RevProxyTransform.Headers {
		// check if header is present and its value is not empty
		val := res.Header.Get(name)
		if val == "" {
			continue
		}
		// Replace scheme
		val = strings.Replace(val, h.Spec.target.Scheme, target_url.Scheme, -1)
		// Replace host
		val = strings.Replace(val, h.Spec.target.Host, target_url.Host, -1)
		// Transform path
		if h.Spec.Proxy.StripListenPath {
			if len(h.Spec.target.Path) != 0 {
				val = strings.Replace(val, h.Spec.target.Path,
					h.Spec.Proxy.ListenPath, -1)
			} else {
				val = strings.Replace(val, req.URL.Path,
					h.Spec.Proxy.ListenPath+req.URL.Path, -1)
			}
		} else {
			if len(h.Spec.target.Path) != 0 {
				val = strings.Replace(val, h.Spec.target.Path, "/", -1)
			}
		}
		setCustomHeader(res.Header, name, val, ignoreCanonical)
	}
	return nil
}

Cognitive complexity: 17, Cyclomatic complexity: 7

Uses: strings.Replace, url.Parse.

func (*HeaderTransform) Init

func (h *HeaderTransform) Init(c interface{}, spec *APISpec) error {
	if err := mapstructure.Decode(c, &h.config); err != nil {
		return err
	}
	h.Spec = spec
	return nil
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: mapstructure.Decode.

func (*HeaderTransform) Name

func (h *HeaderTransform) Name() string {
	return "HeaderTransform"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HostCheckerManager) AmIPolling

func (hc *HostCheckerManager) AmIPolling() bool {
	if hc.store == nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Error("No storage instance set for uptime tests! Disabling poller...")
		return false
	}
	pollerCacheKey := PollerCacheKey
	if hc.Gw.GetConfig().UptimeTests.PollerGroup != "" {
		pollerCacheKey = pollerCacheKey + "." + hc.Gw.GetConfig().UptimeTests.PollerGroup
	}

	activeInstance, err := hc.store.GetKey(pollerCacheKey)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Debug("No Primary instance found, assuming control")
		err := hc.store.SetKey(pollerCacheKey, hc.Id, 15)
		if err != nil {
			log.WithError(err).Error("cannot set key in pollerCacheKey")
		}
		return true
	}

	if activeInstance == hc.Id {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Debug("Primary instance set, I am master")
		err := hc.store.SetKey(pollerCacheKey, hc.Id, 15)	// Reset TTL
		if err != nil {
			log.WithError(err).Error("could not reset TTL in polled cacheKey")
		}
		return true
	}

	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("Active Instance is: ", activeInstance)
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("--- I am: ", hc.Id)
	return false
}

Cognitive complexity: 17, Cyclomatic complexity: 7

Uses: logrus.Fields.

func (*HostCheckerManager) CheckActivePollerLoop

CheckActivePollerLoop manages the state of the HostCheckerManager UptimeTest polling loop, this will start the checking loop if it hasnt been started yet.

The check happens in a 10 seconds interval.

func (hc *HostCheckerManager) CheckActivePollerLoop(ctx context.Context) {
	hc.checkPollerLoop(ctx)
	tick := time.NewTicker(10 * time.Second)
	defer func() {
		tick.Stop()
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Debug("Stopping uptime tests")
	}()
	for {
		select {
		case <-ctx.Done():
			return
		case <-tick.C:
			hc.checkPollerLoop(ctx)
		}
	}
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: logrus.Fields, time.NewTicker, time.Second.

func (*HostCheckerManager) DoServiceDiscoveryListUpdateForID

func (hc *HostCheckerManager) DoServiceDiscoveryListUpdateForID(apiID string) {
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("[HOST CHECKER MANAGER] Getting data from service")
	hostData, err := hc.ListFromService(apiID)
	if err != nil {
		return
	}

	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("[HOST CHECKER MANAGER] Data was: \n", hostData)
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Info("[HOST CHECKER MANAGER] Refreshing uptime tests from service for API: ", apiID)
	hc.UpdateTrackingListByAPIID(hostData, apiID)
}

Cognitive complexity: 5, Cyclomatic complexity: 2

Uses: logrus.Fields.

func (*HostCheckerManager) GenerateCheckerId

func (hc *HostCheckerManager) GenerateCheckerId() {
	hc.Id = uuid.New()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: uuid.New.

func (*HostCheckerManager) HostDown

func (hc *HostCheckerManager) HostDown(urlStr string) bool {
	u, err := url.Parse(urlStr)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Error(err)
	}

	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("Key is: ", PoolerHostSentinelKeyPrefix+u.Host)

	key := PoolerHostSentinelKeyPrefix + u.Host
	// If the node doesn't perform any uptime checks, query the storage:
	if hc.store != nil && !hc.pollerStarted {
		v, _ := hc.store.GetKey(key)
		return v == "1"
	}
	_, ok := hc.unhealthyHostList.Load(key)
	// Found a key, the host is down
	return ok

}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: logrus.Fields, url.Parse.

func (*HostCheckerManager) Init

func (hc *HostCheckerManager) Init(store storage.Handler) {
	hc.store = store
	hc.unhealthyHostList = new(sync.Map)
	hc.resetsInitiated = make(map[string]bool)
	// Generate a new ID for ourselves
	hc.GenerateCheckerId()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: sync.Map.

func (*HostCheckerManager) ListFromService

func (hc *HostCheckerManager) ListFromService(apiID string) ([]HostData, error) {
	spec := hc.Gw.getApiSpec(apiID)
	if spec == nil {
		return nil, errors.New("API ID not found in register")
	}
	sd := ServiceDiscovery{}
	sd.Init(&spec.UptimeTests.Config.ServiceDiscovery)
	data, err := sd.Target(spec.UptimeTests.Config.ServiceDiscovery.QueryEndpoint)

	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Error("[HOST CHECKER MANAGER] Failed to retrieve host list: ", err)
		return nil, err
	}

	// The returned data is a string, so lets unmarshal it:
	checkTargets := make([]apidef.HostCheckObject, 0)
	data0, _ := data.GetIndex(0)
	if err := json.Unmarshal([]byte(data0), &checkTargets); err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Error("[HOST CHECKER MANAGER] Decoder failed: ", err)
		return nil, err
	}

	hostData := make([]HostData, len(checkTargets))
	for i, target := range checkTargets {
		newHostDoc, err := hc.Gw.GlobalHostChecker.PrepareTrackingHost(target, spec.APIID)
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix": "host-check-mgr",
			}).Error("[HOST CHECKER MANAGER] failed to convert to HostData", err)
		} else {
			hostData[i] = newHostDoc
		}
	}
	return hostData, nil
}

Cognitive complexity: 17, Cyclomatic complexity: 6

Uses: apidef.HostCheckObject, errors.New, json.Unmarshal, logrus.Fields.

func (*HostCheckerManager) OnHostBackUp

func (hc *HostCheckerManager) OnHostBackUp(ctx context.Context, report HostHealthReport) {
	key := hc.getHostKey(report)
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("Delete key: ", key)
	hc.store.DeleteKey(key)
	hc.unhealthyHostList.Delete(key)
	spec := hc.Gw.getApiSpec(report.MetaData[UnHealthyHostMetaDataAPIKey])
	if spec == nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Warning("[HOST CHECKER MANAGER] Event can't fire for API that doesn't exist")
		return
	}
	spec.FireEvent(EventHOSTUP, EventHostStatusMeta{
		EventMetaDefault:	EventMetaDefault{Message: "Uptime test succeeded"},
		HostInfo:		report,
	})

	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Warning("[HOST CHECKER MANAGER] Host is UP:   ", report.CheckURL)
}

Cognitive complexity: 7, Cyclomatic complexity: 2

Uses: logrus.Fields.

func (*HostCheckerManager) OnHostDown

func (hc *HostCheckerManager) OnHostDown(ctx context.Context, report HostHealthReport) {
	key := hc.getHostKey(report)
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("Update key: ", key)
	err := hc.store.SetKey(key, "1", int64(hc.checker.checkTimeout*hc.checker.sampleTriggerLimit))
	if err != nil {
		log.WithError(err).Error("Host-Checker could not save key")
	}
	hc.unhealthyHostList.Store(key, 1)
	spec := hc.Gw.getApiSpec(report.MetaData[UnHealthyHostMetaDataAPIKey])
	if spec == nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Warning("[HOST CHECKER MANAGER] Event can't fire for API that doesn't exist")
		return
	}

	spec.FireEvent(EventHOSTDOWN, EventHostStatusMeta{
		EventMetaDefault:	EventMetaDefault{Message: "Uptime test failed"},
		HostInfo:		report,
	})

	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Warning("[HOST CHECKER MANAGER] Host is DOWN: ", report.CheckURL)

	if spec.UptimeTests.Config.ServiceDiscovery.UseDiscoveryService {
		apiID := spec.APIID

		// only do this once
		_, initiated := hc.resetsInitiated[apiID]
		if !initiated {
			hc.resetsInitiated[apiID] = true
			// Lets re-check the uptime tests after x seconds
			go func() {
				log.WithFields(logrus.Fields{
					"prefix": "host-check-mgr",
				}).Printf("[HOST CHECKER MANAGER] Resetting test host list in %v seconds for API: %v", spec.UptimeTests.Config.RecheckWait, apiID)
				time.Sleep(time.Duration(spec.UptimeTests.Config.RecheckWait) * time.Second)
				hc.DoServiceDiscoveryListUpdateForID(apiID)
				delete(hc.resetsInitiated, apiID)
			}()
		}
	}
}

Cognitive complexity: 15, Cyclomatic complexity: 5

Uses: logrus.Fields, time.Duration, time.Second, time.Sleep.

func (*HostCheckerManager) OnHostReport

func (hc *HostCheckerManager) OnHostReport(ctx context.Context, report HostHealthReport) {
	if hc.Gw.GetConfig().UptimeTests.Config.EnableUptimeAnalytics {
		go hc.RecordUptimeAnalytics(report)
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*HostCheckerManager) PrepareTrackingHost

func (hc *HostCheckerManager) PrepareTrackingHost(checkObject apidef.HostCheckObject, apiID string) (HostData, error) {
	// Build the check URL:
	var hostData HostData
	u, err := url.Parse(checkObject.CheckURL)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Error(err)
		return hostData, err
	}

	var bodyData string
	var bodyByteArr []byte
	if len(checkObject.Body) > 0 {
		bodyByteArr, err = base64.StdEncoding.DecodeString(checkObject.Body)
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix": "host-check-mgr",
			}).Error("Failed to load blob data: ", err)
			return hostData, err
		}
		bodyData = string(bodyByteArr)
	}

	hostData = HostData{
		CheckURL:	checkObject.CheckURL,
		MetaData: map[string]string{
			UnHealthyHostMetaDataTargetKey:	checkObject.CheckURL,
			UnHealthyHostMetaDataAPIKey:	apiID,
			UnHealthyHostMetaDataHostKey:	u.Host,
		},
		Method:			checkObject.Method,
		Protocol:		checkObject.Protocol,
		Timeout:		checkObject.Timeout,
		EnableProxyProtocol:	checkObject.EnableProxyProtocol,
		Commands:		checkObject.Commands,
		Headers:		checkObject.Headers,
		Body:			bodyData,
	}

	return hostData, nil
}

Cognitive complexity: 10, Cyclomatic complexity: 4

Uses: base64.StdEncoding, logrus.Fields, url.Parse.

func (*HostCheckerManager) RecordUptimeAnalytics

RecordHit will store an AnalyticsRecord in Redis

func (hc *HostCheckerManager) RecordUptimeAnalytics(report HostHealthReport) error {
	// If we are obfuscating API Keys, store the hashed representation (config check handled in hashing function)

	spec := hc.Gw.getApiSpec(report.MetaData[UnHealthyHostMetaDataAPIKey])
	orgID := ""
	if spec != nil {
		orgID = spec.OrgID
	}

	t := time.Now()

	var serverError bool
	if report.ResponseCode > http.StatusOK {
		serverError = true
	}

	newAnalyticsRecord := UptimeReportData{
		URL:		report.CheckURL,
		RequestTime:	int64(report.Latency),
		ResponseCode:	report.ResponseCode,
		TCPError:	report.IsTCPError,
		ServerError:	serverError,
		Day:		t.Day(),
		Month:		t.Month(),
		Year:		t.Year(),
		Hour:		t.Hour(),
		Minute:		t.Minute(),
		TimeStamp:	t,
		APIID:		report.MetaData[UnHealthyHostMetaDataAPIKey],
		OrgID:		orgID,
	}

	// For anlytics purposes, we need a code
	if report.IsTCPError {
		newAnalyticsRecord.ResponseCode = 521
	}

	newAnalyticsRecord.SetExpiry(spec.UptimeTests.Config.ExpireUptimeAnalyticsAfter)

	encoded, err := msgpack.Marshal(newAnalyticsRecord)

	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Error("Error encoding uptime data:", err)
		return err
	}

	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("Recording uptime stat")
	hc.store.AppendToSet(UptimeAnalytics_KEYNAME, string(encoded))
	return nil
}

Cognitive complexity: 11, Cyclomatic complexity: 5

Uses: http.StatusOK, logrus.Fields, msgpack.Marshal, time.Now.

func (*HostCheckerManager) Start

func (hc *HostCheckerManager) Start(ctx context.Context) {
	// Start loop to check if we are active instance
	if hc != nil {
		go hc.CheckActivePollerLoop(ctx)
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*HostCheckerManager) StartPoller

func (hc *HostCheckerManager) StartPoller(ctx context.Context) {
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("---> Initialising checker")

	// If we are restarting, we want to retain the host list
	hc.checkerMu.Lock()
	if hc.checker == nil {
		hc.checker = &HostUptimeChecker{Gw: hc.Gw}
	}

	hc.checker.Init(
		hc.Gw.GetConfig().UptimeTests.Config.CheckerPoolSize,
		hc.Gw.GetConfig().UptimeTests.Config.FailureTriggerSampleSize,
		hc.Gw.GetConfig().UptimeTests.Config.TimeWait,
		hc.currentHostList,
		HostCheckCallBacks{
			Up:	hc.OnHostBackUp,
			Fail:	hc.OnHostDown,
			Ping:	hc.OnHostReport,
		},
	)

	// Start the check loop
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("---> Starting checker")

	hc.checker.Start(ctx)

	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("---> Checker started.")

	hc.checkerMu.Unlock()
}

Cognitive complexity: 7, Cyclomatic complexity: 2

Uses: logrus.Fields.

func (*HostCheckerManager) StopPoller

func (hc *HostCheckerManager) StopPoller() {
	if hc == nil {
		return
	}

	hc.checkerMu.Lock()
	hc.checker.Stop()
	hc.checkerMu.Unlock()
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*HostCheckerManager) UpdateTrackingList

func (hc *HostCheckerManager) UpdateTrackingList(hd []HostData) {
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("--- Setting tracking list up")
	newHostList := make(map[string]HostData)
	for _, host := range hd {
		newHostList[host.CheckURL] = host
	}

	hc.checkerMu.Lock()
	hc.currentHostList = newHostList
	if hc.checker != nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Debug("Reset initiated")
		hc.checker.ResetList(newHostList)
	}
	hc.checkerMu.Unlock()
}

Cognitive complexity: 7, Cyclomatic complexity: 3

Uses: logrus.Fields.

func (*HostCheckerManager) UpdateTrackingListByAPIID

func (hc *HostCheckerManager) UpdateTrackingListByAPIID(hd []HostData, apiId string) {
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Debug("--- Setting tracking list up for ID: ", apiId)
	newHostList := make(map[string]HostData)

	hc.checkerMu.Lock()
	for _, existingHost := range hc.currentHostList {
		if existingHost.MetaData[UnHealthyHostMetaDataAPIKey] != apiId {
			// Add the old check list that excludes this API
			newHostList[existingHost.CheckURL] = existingHost
		}
	}

	// Add the new list for this APIID:
	for _, host := range hd {
		newHostList[host.CheckURL] = host
	}

	hc.currentHostList = newHostList
	if hc.checker != nil {
		log.WithFields(logrus.Fields{
			"prefix": "host-check-mgr",
		}).Debug("Reset initiated")
		hc.checker.ResetList(newHostList)
	}
	hc.checkerMu.Unlock()
	log.WithFields(logrus.Fields{
		"prefix": "host-check-mgr",
	}).Info("--- Queued tracking list update for API: ", apiId)
}

Cognitive complexity: 13, Cyclomatic complexity: 5

Uses: logrus.Fields.

func (*HostUptimeChecker) CheckHost

func (h *HostUptimeChecker) CheckHost(toCheck HostData) {
	log.Debug("[HOST CHECKER] Checking: ", toCheck.CheckURL)

	t1 := time.Now()
	report := HostHealthReport{
		HostData: toCheck,
	}
	switch toCheck.Protocol {
	case "tcp", "tls":
		host := toCheck.CheckURL
		base := toCheck.Protocol + "://"
		if !strings.HasPrefix(host, base) {
			host = base + host
		}
		u, err := url.Parse(host)
		if err != nil {
			log.Error("Could not parse host: ", err)
			return
		}
		var ls net.Conn
		var d net.Dialer
		d.Timeout = toCheck.Timeout
		if toCheck.Protocol == "tls" {
			ls, err = tls.DialWithDialer(&d, "tls", u.Host, nil)
		} else {
			ls, err = d.Dial("tcp", u.Host)
		}
		if err != nil {
			log.Error("Could not connect to host: ", err)
			report.IsTCPError = true
			break
		}
		if toCheck.EnableProxyProtocol {
			log.Debug("using proxy protocol")
			ls = proxyproto.NewConn(ls)
		}
		defer ls.Close()
		for _, cmd := range toCheck.Commands {
			switch cmd.Name {
			case "send":
				log.Debugf("%s: sending %s", host, cmd.Message)
				_, err = ls.Write([]byte(cmd.Message))
				if err != nil {
					log.Errorf("Failed to send %s :%v", cmd.Message, err)
					report.IsTCPError = true
					break
				}
			case "expect":
				buf := make([]byte, len(cmd.Message))
				_, err = ls.Read(buf)
				if err != nil {
					log.Errorf("Failed to read %s :%v", cmd.Message, err)
					report.IsTCPError = true
					break
				}
				g := string(buf)
				if g != cmd.Message {
					log.Errorf("Failed expectation  expected %s got %s", cmd.Message, g)
					report.IsTCPError = true
					break
				}
				log.Debugf("%s: received %s", host, cmd.Message)
			}
		}
		report.ResponseCode = http.StatusOK
	default:
		useMethod := toCheck.Method
		if toCheck.Method == "" {
			useMethod = http.MethodGet
		}
		req, err := http.NewRequest(useMethod, toCheck.CheckURL, strings.NewReader(toCheck.Body))
		if err != nil {
			log.Error("Could not create request: ", err)
			return
		}
		ignoreCanonical := h.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
		for headerName, headerValue := range toCheck.Headers {
			setCustomHeader(req.Header, headerName, headerValue, ignoreCanonical)
		}
		req.Header.Set("Connection", "close")
		h.Gw.HostCheckerClient.Transport = &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify:	h.Gw.GetConfig().ProxySSLInsecureSkipVerify,
				MaxVersion:		h.Gw.GetConfig().ProxySSLMaxVersion,
			},
		}
		if toCheck.Timeout != 0 {
			h.Gw.HostCheckerClient.Timeout = toCheck.Timeout
		}
		response, err := h.Gw.HostCheckerClient.Do(req)
		if err != nil {
			report.IsTCPError = true
			break
		}
		response.Body.Close()
		report.ResponseCode = response.StatusCode
	}

	millisec := DurationToMillisecond(time.Since(t1))
	report.Latency = millisec
	if report.IsTCPError {
		h.errorChan <- report
		return
	}

	if report.ResponseCode != http.StatusOK {
		h.errorChan <- report
		return
	}

	// host is healthy, report it
	h.okChan <- report
}

Cognitive complexity: 14, Cyclomatic complexity: 7

Uses: http.MethodGet, http.NewRequest, http.StatusOK, http.Transport, net.Conn, net.Dialer, proxyproto.NewConn, strings.HasPrefix, strings.NewReader, time.Now, time.Since, tls.Config, tls.DialWithDialer, url.Parse.

func (*HostUptimeChecker) HostCheckLoop

func (h *HostUptimeChecker) HostCheckLoop(ctx context.Context) {
	defer func() {
		log.Info("[HOST CHECKER] Checker stopped")
	}()
	if h.Gw.isRunningTests() {
		for {
			select {
			case <-ctx.Done():
				return
			case <-h.Gw.HostCheckTicker:
				h.execCheck()
			}
		}
	} else {
		tick := time.NewTicker(h.getStaggeredTime())
		defer tick.Stop()
		for {
			select {
			case <-ctx.Done():
				return
			case <-tick.C:
				h.execCheck()
			}
		}
	}
}

Cognitive complexity: 15, Cyclomatic complexity: 8

Uses: time.NewTicker.

func (*HostUptimeChecker) HostReporter

func (h *HostUptimeChecker) HostReporter(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			h.Stop()
			log.Debug("[HOST CHECKER] Received cancel signal")
			return
		case okHost := <-h.okChan:
			// check if the the host url is in the sample map
			if hostSample, found := h.samples.Load(okHost.CheckURL); found {
				sample := hostSample.(HostSample)
				//if it reached the h.sampleTriggerLimit, we're going to start decreasing the count value
				if sample.reachedLimit {
					newCount := sample.count - 1

					if newCount <= 0 {
						//if the count-1 is equals to zero, it means that the host is fully up.

						h.samples.Delete(okHost.CheckURL)
						log.Warning("[HOST CHECKER] [HOST UP]: ", okHost.CheckURL)
						go h.cb.Up(ctx, okHost)
					} else {
						//in another case, we are one step closer. We just update the count number
						sample.count = newCount
						log.Warning("[HOST CHECKER] [HOST UP BUT NOT REACHED LIMIT]: ", okHost.CheckURL)
						h.samples.Store(okHost.CheckURL, sample)
					}
				}
			}
			if h.cb.Ping != nil {
				go h.cb.Ping(ctx, okHost)
			}

		case failedHost := <-h.errorChan:
			sample := HostSample{
				count: 1,
			}

			//If a host fails, we check if it has failed already
			if hostSample, found := h.samples.Load(failedHost.CheckURL); found {
				sample = hostSample.(HostSample)
				// we add THIS failure to the count
				sample.count = sample.count + 1
			}

			if sample.count >= h.sampleTriggerLimit {
				// if it reached the h.sampleTriggerLimit, it means the host is down for us. We update the reachedLimit flag and store it in the sample map
				log.Warning("[HOST CHECKER] [HOST DOWN]: ", failedHost.CheckURL)

				//if this is the first time it reached the h.sampleTriggerLimit, the value of the reachedLimit flag is stored with the new count
				if sample.reachedLimit == false {
					sample.reachedLimit = true
					h.samples.Store(failedHost.CheckURL, sample)
				}

				//we call the failureCallback to keep the redis key and the host checker manager updated
				go h.cb.Fail(ctx, failedHost)

			} else {
				//if it failed but not reached the h.sampleTriggerLimit yet, we just add the counter to the map.
				log.Warning("[HOST CHECKER] [HOST DOWN BUT NOT REACHED LIMIT]: ", failedHost.CheckURL)
				h.samples.Store(failedHost.CheckURL, sample)
			}

			if h.cb.Ping != nil {
				go h.cb.Ping(ctx, failedHost)
			}
		}
	}
}

Cognitive complexity: 27, Cyclomatic complexity: 13

func (*HostUptimeChecker) Init

func (h *HostUptimeChecker) Init(workers, triggerLimit, timeout int, hostList map[string]HostData, cb HostCheckCallBacks) {
	h.samples = new(sync.Map)
	h.errorChan = make(chan HostHealthReport)
	h.okChan = make(chan HostHealthReport)
	h.HostList = hostList
	h.unHealthyList = make(map[string]bool)
	h.cb = cb

	h.workerPoolSize = workers
	if workers == 0 {
		h.workerPoolSize = defaultWorkerPoolSize
	}

	h.sampleTriggerLimit = triggerLimit
	if triggerLimit == 0 {
		h.sampleTriggerLimit = defaultSampletTriggerLimit
	}

	h.checkTimeout = timeout
	if timeout == 0 {
		h.checkTimeout = defaultTimeout
	}

	log.Debug("[HOST CHECKER] Config:TriggerLimit: ", h.sampleTriggerLimit)
	log.Debug("[HOST CHECKER] Config:Timeout: ~", h.checkTimeout)
	log.Debug("[HOST CHECKER] Config:WorkerPool: ", h.workerPoolSize)

	h.pool = tunny.NewFunc(h.workerPoolSize, func(hostData interface{}) interface{} {
		input, _ := hostData.(HostData)
		h.CheckHost(input)
		return nil
	})

	log.Debug("[HOST CHECKER] Init complete")
}

Cognitive complexity: 9, Cyclomatic complexity: 4

Uses: sync.Map, tunny.NewFunc.

func (*HostUptimeChecker) ResetList

func (h *HostUptimeChecker) ResetList(hostList map[string]HostData) {
	h.resetListMu.Lock()
	h.doResetList = true
	h.newList = hostList
	h.resetListMu.Unlock()
	log.Debug("[HOST CHECKER] Checker reset queued!")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HostUptimeChecker) Start

func (h *HostUptimeChecker) Start(ctx context.Context) {
	// Start the loop that checks for bum hosts
	log.Debug("[HOST CHECKER] Starting...")
	go h.HostCheckLoop(ctx)
	log.Debug("[HOST CHECKER] Check loop started...")
	go h.HostReporter(ctx)
	log.Debug("[HOST CHECKER] Host reporter started...")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*HostUptimeChecker) Stop

func (h *HostUptimeChecker) Stop() {
	if h == nil {
		return
	}

	was := atomic.SwapInt32(&h.isClosed, CLOSED)
	if was == OPEN {
		eraseSyncMap(h.samples)

		log.Info("[HOST CHECKER] Stopping poller")

		if h.pool != nil && h.pool.GetSize() > 0 {
			h.pool.Close()
		}
	}
}

Cognitive complexity: 6, Cyclomatic complexity: 5

Uses: atomic.SwapInt32.

func (*IPBlackListMiddleware) EnabledForSpec

func (i *IPBlackListMiddleware) EnabledForSpec() bool {
	enabled := !i.Spec.APIDefinition.IPAccessControlDisabled || i.Spec.APIDefinition.EnableIpBlacklisting

	return enabled && len(i.Spec.APIDefinition.BlacklistedIPs) > 0
}

Cognitive complexity: 0, Cyclomatic complexity: 3

func (*IPBlackListMiddleware) Name

func (i *IPBlackListMiddleware) Name() string {
	return "IPBlackListMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*IPBlackListMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (i *IPBlackListMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	remoteIP := net.ParseIP(request.RealIP(r))

	// Enabled, check incoming IP address
	for _, ip := range i.Spec.BlacklistedIPs {
		// Might be CIDR, try this one first then fallback to IP parsing later
		blockedIP, blockedNet, err := net.ParseCIDR(ip)
		if err != nil {
			blockedIP = net.ParseIP(ip)
		}

		// Check CIDR if possible
		if blockedNet != nil && blockedNet.Contains(remoteIP) {

			return i.handleError(r, remoteIP.String())
		}

		// We parse the IP to manage IPv4 and IPv6 easily
		if blockedIP.Equal(remoteIP) {
			return i.handleError(r, remoteIP.String())
		}
	}

	return nil, http.StatusOK
}

Cognitive complexity: 10, Cyclomatic complexity: 6

Uses: http.StatusOK, net.ParseCIDR, net.ParseIP, request.RealIP.

func (*IPWhiteListMiddleware) EnabledForSpec

func (i *IPWhiteListMiddleware) EnabledForSpec() bool {
	enabled := !i.Spec.APIDefinition.IPAccessControlDisabled || i.Spec.APIDefinition.EnableIpWhiteListing

	return enabled && len(i.Spec.APIDefinition.AllowedIPs) > 0
}

Cognitive complexity: 0, Cyclomatic complexity: 3

func (*IPWhiteListMiddleware) Name

func (i *IPWhiteListMiddleware) Name() string {
	return "IPWhiteListMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*IPWhiteListMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (i *IPWhiteListMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	remoteIP := net.ParseIP(request.RealIP(r))

	// Enabled, check incoming IP address
	for _, ip := range i.Spec.AllowedIPs {
		// Might be CIDR, try this one first then fallback to IP parsing later
		allowedIP, allowedNet, err := net.ParseCIDR(ip)
		if err != nil {
			allowedIP = net.ParseIP(ip)
		}

		// Check CIDR if possible
		if allowedNet != nil && allowedNet.Contains(remoteIP) {
			// matched, pass through
			return nil, http.StatusOK
		}

		// We parse the IP to manage IPv4 and IPv6 easily
		if allowedIP.Equal(remoteIP) {
			// matched, pass through
			return nil, http.StatusOK
		}
	}

	// Fire Authfailed Event
	AuthFailed(i, r, remoteIP.String())
	// Report in health check
	reportHealthValue(i.Spec, KeyFailure, "-1")

	// Not matched, fail
	return errors.New("access from this IP has been disallowed"), http.StatusForbidden
}

Cognitive complexity: 10, Cyclomatic complexity: 6

Uses: errors.New, http.StatusForbidden, http.StatusOK, net.ParseCIDR, net.ParseIP, request.RealIP.

func (*JSVM) DeInit

func (j *JSVM) DeInit() {
	j.Spec = nil
	j.Log = nil
	j.RawLog = nil
	j.Gw = nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*JSVM) Init

Init creates the JSVM with the core library and sets up a default timeout.

func (j *JSVM) Init(spec *APISpec, logger *logrus.Entry, gw *Gateway) {
	vm := otto.New()
	j.Gw = gw
	logger = logger.WithField("prefix", "jsvm")

	// Init TykJS namespace, constructors etc.
	if _, err := vm.Run(coreJS); err != nil {
		logger.WithError(err).Error("Could not load TykJS")
		return
	}

	// Load user's TykJS on top, if any
	if path := gw.GetConfig().TykJSPath; path != "" {
		f, err := os.Open(path)
		if err == nil {
			_, err = vm.Run(f)
			f.Close()

			if err != nil {
				logger.WithError(err).Error("Could not load user's TykJS")
			}
		}
	}

	j.VM = vm
	j.Spec = spec

	// Add environment API
	j.LoadTykJSApi()

	if jsvmTimeout := gw.GetConfig().JSVMTimeout; jsvmTimeout <= 0 {
		j.Timeout = time.Duration(defaultJSVMTimeout) * time.Second
		logger.Debugf("Default JSVM timeout used: %v", j.Timeout)
	} else {
		j.Timeout = time.Duration(jsvmTimeout) * time.Second
		logger.Debugf("Custom JSVM timeout: %v", j.Timeout)
	}

	j.Log = logger	// use the global logger by default
	j.RawLog = rawLog
}

Cognitive complexity: 12, Cyclomatic complexity: 6

Uses: os.Open, otto.New, time.Duration, time.Second.

func (*JSVM) LoadJSPaths

LoadJSPaths will load JS classes and functionality in to the VM by file

func (j *JSVM) LoadJSPaths(paths []string, prefix string) {
	for _, mwPath := range paths {
		if prefix != "" {
			mwPath = filepath.Join(prefix, mwPath)
		}
		extension := filepath.Ext(mwPath)
		if !strings.Contains(extension, ".js") {
			j.Log.Errorf("Unsupported extension '%s' (%s)", extension, mwPath)
			continue
		}
		j.Log.Info("Loading JS File: ", mwPath)
		f, err := os.Open(mwPath)
		if err != nil {
			j.Log.WithError(err).Error("Failed to open JS middleware file")
			continue
		}
		if _, err := j.VM.Run(f); err != nil {
			j.Log.WithError(err).Error("Failed to load JS middleware")
		}
		f.Close()
	}
}

Cognitive complexity: 11, Cyclomatic complexity: 6

Uses: filepath.Ext, filepath.Join, os.Open, strings.Contains.

func (*JSVM) LoadTykJSApi

func (j *JSVM) LoadTykJSApi() {
	// Enable a log
	j.VM.Set("log", func(call otto.FunctionCall) otto.Value {
		j.Log.WithFields(logrus.Fields{
			"type": "log-msg",
		}).Info(call.Argument(0).String())
		return otto.Value{}
	})
	j.VM.Set("rawlog", func(call otto.FunctionCall) otto.Value {
		j.RawLog.Print(call.Argument(0).String() + "\n")
		return otto.Value{}
	})

	// these two needed for non-utf8 bodies
	j.VM.Set("b64dec", func(call otto.FunctionCall) otto.Value {
		in := call.Argument(0).String()
		out, err := base64.StdEncoding.DecodeString(in)

		// Fallback to RawStdEncoding:
		if err != nil {
			out, err = base64.RawStdEncoding.DecodeString(in)
			if err != nil {
				j.Log.WithError(err).Error("Failed to base64 decode")
				return otto.Value{}
			}
		}
		returnVal, err := j.VM.ToValue(string(out))
		if err != nil {
			j.Log.WithError(err).Error("Failed to base64 decode")
			return otto.Value{}
		}
		return returnVal
	})
	j.VM.Set("b64enc", func(call otto.FunctionCall) otto.Value {
		in := []byte(call.Argument(0).String())
		out := base64.StdEncoding.EncodeToString(in)
		returnVal, err := j.VM.ToValue(out)
		if err != nil {
			j.Log.WithError(err).Error("Failed to base64 encode")
			return otto.Value{}
		}
		return returnVal
	})

	j.VM.Set("rawb64dec", func(call otto.FunctionCall) otto.Value {
		in := call.Argument(0).String()
		out, err := base64.RawStdEncoding.DecodeString(in)
		if err != nil {
			j.Log.WithError(err).Error("Failed to base64 decode")
			return otto.Value{}
		}
		returnVal, err := j.VM.ToValue(string(out))
		if err != nil {
			j.Log.WithError(err).Error("Failed to base64 decode")
			return otto.Value{}
		}
		return returnVal
	})
	j.VM.Set("rawb64enc", func(call otto.FunctionCall) otto.Value {
		in := []byte(call.Argument(0).String())
		out := base64.RawStdEncoding.EncodeToString(in)
		returnVal, err := j.VM.ToValue(out)
		if err != nil {
			j.Log.WithError(err).Error("Failed to base64 encode")
			return otto.Value{}
		}
		return returnVal
	})
	ignoreCanonical := j.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
	// Enable the creation of HTTP Requsts
	j.VM.Set("TykMakeHttpRequest", func(call otto.FunctionCall) otto.Value {
		jsonHRO := call.Argument(0).String()
		if jsonHRO == "undefined" {
			// Nope, return nothing
			return otto.Value{}
		}
		hro := TykJSHttpRequest{}
		if err := json.Unmarshal([]byte(jsonHRO), &hro); err != nil {
			j.Log.WithError(err).Error("JSVM: Failed to deserialise HTTP Request object")
			return otto.Value{}
		}

		// Make the request
		domain := hro.Domain
		data := url.Values{}
		for k, v := range hro.FormData {
			data.Set(k, v)
		}

		u, _ := url.ParseRequestURI(domain + hro.Resource)
		urlStr := u.String()	// "https://api.com/user/"

		var d string
		if hro.Body != "" {
			d = hro.Body
		} else if len(hro.FormData) > 0 {
			d = data.Encode()
		}

		r, _ := http.NewRequest(hro.Method, urlStr, nil)

		if d != "" {
			r, _ = http.NewRequest(hro.Method, urlStr, strings.NewReader(d))
		}

		for k, v := range hro.Headers {
			setCustomHeader(r.Header, k, v, ignoreCanonical)
		}
		r.Close = true

		maxSSLVersion := j.Gw.GetConfig().ProxySSLMaxVersion
		if j.Spec.Proxy.Transport.SSLMaxVersion > 0 {
			maxSSLVersion = j.Spec.Proxy.Transport.SSLMaxVersion
		}

		tr := &http.Transport{TLSClientConfig: &tls.Config{
			MaxVersion: maxSSLVersion,
		}}

		if cert := j.Gw.getUpstreamCertificate(r.Host, j.Spec); cert != nil {
			tr.TLSClientConfig.Certificates = []tls.Certificate{*cert}
		}

		if j.Gw.GetConfig().ProxySSLInsecureSkipVerify {
			tr.TLSClientConfig.InsecureSkipVerify = true
		}

		if j.Spec.Proxy.Transport.SSLInsecureSkipVerify {
			tr.TLSClientConfig.InsecureSkipVerify = true
		}

		tr.DialTLS = j.Gw.customDialTLSCheck(j.Spec, tr.TLSClientConfig)

		tr.Proxy = proxyFromAPI(j.Spec)

		// using new Client each time should be ok, since we closing connection every time
		client := &http.Client{Transport: tr}
		resp, err := client.Do(r)
		if err != nil {
			j.Log.WithError(err).Error("Request failed")
			return otto.Value{}
		}

		body, _ := ioutil.ReadAll(resp.Body)
		bodyStr := string(body)
		tykResp := TykJSHttpResponse{
			Code:		resp.StatusCode,
			Body:		bodyStr,
			Headers:	resp.Header,
			CodeComp:	resp.StatusCode,
			BodyComp:	bodyStr,
			HeadersComp:	resp.Header,
		}

		retAsStr, _ := json.Marshal(tykResp)
		returnVal, err := j.VM.ToValue(string(retAsStr))
		if err != nil {
			j.Log.WithError(err).Error("Failed to encode return value")
			return otto.Value{}
		}

		return returnVal
	})

	// Expose Setters and Getters in the REST API for a key:
	j.VM.Set("TykGetKeyData", func(call otto.FunctionCall) otto.Value {
		apiKey := call.Argument(0).String()
		apiId := call.Argument(1).String()

		obj, _ := j.Gw.handleGetDetail(apiKey, apiId, "", false)
		bs, _ := json.Marshal(obj)

		returnVal, err := j.VM.ToValue(string(bs))
		if err != nil {
			j.Log.WithError(err).Error("Failed to encode return value")
			return otto.Value{}
		}

		return returnVal
	})

	j.VM.Set("TykSetKeyData", func(call otto.FunctionCall) otto.Value {
		apiKey := call.Argument(0).String()
		encoddedSession := call.Argument(1).String()
		suppressReset := call.Argument(2).String()

		newSession := user.SessionState{}
		err := json.Unmarshal([]byte(encoddedSession), &newSession)
		if err != nil {
			j.Log.WithError(err).Error("Failed to decode the sesison data")
			return otto.Value{}
		}

		j.Gw.doAddOrUpdate(apiKey, &newSession, suppressReset == "1", false)
		return otto.Value{}
	})

	// Batch request method
	unsafeBatchHandler := BatchRequestHandler{Gw: j.Gw}
	j.VM.Set("TykBatchRequest", func(call otto.FunctionCall) otto.Value {
		requestSet := call.Argument(0).String()
		j.Log.Debug("Batch input is: ", requestSet)
		bs, err := unsafeBatchHandler.ManualBatchRequest([]byte(requestSet))
		if err != nil {
			j.Log.WithError(err).Error("Batch request error")
			return otto.Value{}
		}

		returnVal, err := j.VM.ToValue(string(bs))
		if err != nil {
			j.Log.WithError(err).Error("Failed to encode return value")
			return otto.Value{}
		}

		return returnVal
	})

	j.VM.Run(`function TykJsResponse(response, session_meta) {
		return JSON.stringify({Response: response, SessionMeta: session_meta})
	}`)
}

Cognitive complexity: 89, Cyclomatic complexity: 25

Uses: base64.RawStdEncoding, base64.StdEncoding, http.Client, http.NewRequest, http.Transport, ioutil.ReadAll, json.Marshal, json.Unmarshal, logrus.Fields, otto.FunctionCall, otto.Value, strings.NewReader, tls.Certificate, tls.Config, url.ParseRequestURI, url.Values, user.SessionState.

func (*JSVMEventHandler) HandleEvent

HandleEvent will be fired when the event handler instance is found in an APISpec EventPaths object during a request chain

func (l *JSVMEventHandler) HandleEvent(em config.EventMessage) {
	// JSON-encode the event data object
	msgAsJSON, err := json.Marshal(em)
	if err != nil {
		log.Error("Failed to encode event data: ", err)
		return
	}

	// Execute the method name with the JSON object
	_, err = l.Gw.GlobalEventsJSVM.VM.Run(l.conf.MethodName + `.DoProcessEvent(` + string(msgAsJSON) + `,` + l.SpecJSON + `);`)
	if err != nil {
		log.WithError(err).Error("executing JSVM method")
	}
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: json.Marshal.

func (*JSVMEventHandler) Init

Init initializes the JSVMEventHandler by setting the method name and global values required for the JavaScript VM.

func (l *JSVMEventHandler) Init(handlerConf any) error {
	var err error
	if err = l.conf.Scan(handlerConf); err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "jsvm_event_handler",
		}).Error("Problem getting configuration, skipping. ", err)
		return err
	}

	if l.conf.Disabled {
		log.WithFields(logrus.Fields{
			"prefix": "jsvm_event_handler",
		}).Infof("skipping disabled jsvm event handler with method name %s at path %s", l.conf.MethodName, l.conf.Path)
		return ErrEventHandlerDisabled
	}

	// Set the VM globals
	globalVals := JSVMContextGlobal{
		APIID:	l.Spec.APIID,
		OrgID:	l.Spec.OrgID,
	}

	gValAsJSON, err := json.Marshal(globalVals)
	if err != nil {
		log.Error("Failed to marshal globals! ", err)
	}

	l.SpecJSON = string(gValAsJSON)
	return nil
}

Cognitive complexity: 9, Cyclomatic complexity: 4

Uses: json.Marshal, logrus.Fields.

func (*JWTMiddleware) EnabledForSpec

func (k *JWTMiddleware) EnabledForSpec() bool {
	return k.Spec.EnableJWT
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*JWTMiddleware) Name

func (k *JWTMiddleware) Name() string {
	return "JWTMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*JWTMiddleware) ProcessRequest

func (k *JWTMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	logger := k.Logger()
	var tykId string

	rawJWT, config := k.getAuthToken(k.getAuthType(), r)

	if rawJWT == "" {
		// No header value, fail
		logger.Info("Attempted access with malformed header, no JWT auth header found.")

		log.Debug("Looked in: ", config.AuthHeaderName)
		log.Debug("Raw data was: ", rawJWT)
		log.Debug("Headers are: ", r.Header)

		k.reportLoginFailure(tykId, r)
		return errors.New("Authorization field missing"), http.StatusBadRequest
	}

	// enable bearer token format
	rawJWT = stripBearer(rawJWT)

	// Use own validation logic, see below
	parser := jwt.NewParser(jwt.WithoutClaimsValidation())

	// Verify the token
	token, err := parser.Parse(rawJWT, func(token *jwt.Token) (interface{}, error) {
		// Don't forget to validate the alg is what you expect:
		if err := assertSigningMethod(k.Spec.JWTSigningMethod, token); err != nil {
			return nil, err
		}

		val, err := k.getSecretToVerifySignature(r, token)
		if err != nil {
			k.Logger().WithError(err).Error("Couldn't get token")
			return nil, err
		}

		return parseJWTKey(k.Spec.JWTSigningMethod, val)
	})

	if err == nil && token.Valid {
		if jwtErr := k.timeValidateJWTClaims(token.Claims.(jwt.MapClaims)); jwtErr != nil {
			return errors.New("Key not authorized: " + jwtErr.Error()), http.StatusUnauthorized
		}

		// Token is valid - let's move on

		// Are we mapping to a central JWT Secret?
		hasJWTSource := k.Spec.JWTSource != ""
		hasJwksURIs := len(k.Spec.JWTJwksURIs) > 0

		if hasJWTSource || hasJwksURIs {
			return k.processCentralisedJWT(r, token)
		}

		// No, let's try one-to-one mapping
		return k.processOneToOneTokenMap(r, token)
	}

	logger.Info("Attempted JWT access with non-existent key.")
	k.reportLoginFailure(tykId, r)
	if err != nil {
		logger.WithError(err).Error("JWT validation error")
		errorDetails := strings.Split(err.Error(), ":")
		if errorDetails[0] == UnexpectedSigningMethod {
			return errors.New(MsgKeyNotAuthorizedUnexpectedSigningMethod), http.StatusForbidden
		}
	}
	return errors.New("Key not authorized"), http.StatusForbidden
}

Cognitive complexity: 21, Cyclomatic complexity: 12

Uses: errors.New, http.StatusBadRequest, http.StatusForbidden, http.StatusOK, http.StatusUnauthorized, strings.Split.

func (*KeyExpired) Name

func (k *KeyExpired) Name() string {
	return "KeyExpired"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*KeyExpired) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (k *KeyExpired) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	logger := k.Logger()
	session := ctxGetSession(r)
	if session == nil {
		return errors.New("Session state is missing or unset! Please make sure that auth headers are properly applied"), http.StatusBadRequest
	}

	token := ctxGetAuthToken(r)
	if session.IsInactive {
		logger.Info("Attempted access from inactive key.")
		// Fire a key expired event
		k.FireEvent(EventKeyExpired, EventKeyFailureMeta{
			EventMetaDefault:	EventMetaDefault{Message: "Attempted access from inactive key.", OriginatingRequest: EncodeRequestToEvent(r)},
			Path:			r.URL.Path,
			Origin:			request.RealIP(r),
			Key:			token,
		})

		// Report in health check
		reportHealthValue(k.Spec, KeyFailure, "-1")

		return errors.New("Key is inactive, please renew"), http.StatusForbidden
	}

	if !k.Spec.AuthManager.KeyExpired(session) {
		return nil, http.StatusOK
	}
	logger.Info("Attempted access from expired key.")

	k.FireEvent(EventKeyExpired, EventKeyFailureMeta{
		EventMetaDefault:	EventMetaDefault{Message: "Attempted access from expired key.", OriginatingRequest: EncodeRequestToEvent(r)},
		Path:			r.URL.Path,
		Origin:			request.RealIP(r),
		Key:			token,
	})
	// Report in health check
	reportHealthValue(k.Spec, KeyFailure, "-1")

	return errors.New("Key has expired, please renew"), http.StatusUnauthorized
}

Cognitive complexity: 13, Cyclomatic complexity: 5

Uses: errors.New, http.StatusBadRequest, http.StatusForbidden, http.StatusOK, http.StatusUnauthorized, request.RealIP.

func (*LDAPStorageHandler) Connect

func (l *LDAPStorageHandler) Connect() bool {
	conn := ldap.NewLDAPConnection(l.LDAPServer, l.LDAPPort)
	if err := conn.Connect(); err != nil {
		log.Error("LDAP server connection failed: ", err)
		return false
	}
	log.Info("LDAP: Connection established")
	l.store = conn
	return true
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: ldap.NewLDAPConnection.

func (*LDAPStorageHandler) Decrement

func (l *LDAPStorageHandler) Decrement(keyName string) {
	l.notifyReadOnly()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) DeleteAllKeys

func (r *LDAPStorageHandler) DeleteAllKeys() bool {
	log.Warning("Not implementated")
	return false
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) DeleteKey

func (l *LDAPStorageHandler) DeleteKey(cn string) bool {
	return l.notifyReadOnly()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) DeleteKeys

func (l *LDAPStorageHandler) DeleteKeys(keys []string) bool {
	return l.notifyReadOnly()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) DeleteRawKey

func (l *LDAPStorageHandler) DeleteRawKey(cn string) bool {
	return l.notifyReadOnly()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) DeleteRawKeys

func (l *LDAPStorageHandler) DeleteRawKeys([]string) bool	{ return l.notifyReadOnly() }

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) GetExp

func (l *LDAPStorageHandler) GetExp(cn string) (int64, error) {
	log.Warning("Not implementated")
	return 0, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) GetKey

func (l *LDAPStorageHandler) GetKey(filter string) (string, error) {
	log.Debug("Searching for filter: ", filter)

	useFilter := strings.Replace(l.SearchString, "TYKKEYID", filter, 1)
	log.Warning("Search filter is: ", useFilter)

	search_request := ldap.NewSearchRequest(
		l.BaseDN,
		ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
		useFilter,
		l.Attributes,
		nil)

	sr, err := l.store.Search(search_request)
	if err != nil {
		log.Debug("LDAP Key search failed: ", err)
		return "", err
	}

	if len(sr.Entries) == 0 {
		return "", nil
	}

	log.Debug("Found Key: ", sr.Entries[0])

	entry := sr.Entries[0]

	if entry.Attributes == nil {
		log.Error("LDAP: No attributes found to check for session state. Failing")
		return "", errors.New("Attributes for entry are empty")
	}

	for _, attr := range entry.Attributes {
		if attr.Name == l.SessionAttributeName {
			log.Debug("Found session data: ", attr.Values[0])
			return attr.Values[0], nil
		}
	}

	return "", nil
}

Cognitive complexity: 11, Cyclomatic complexity: 6

Uses: errors.New, ldap.DerefAlways, ldap.NewSearchRequest, ldap.ScopeWholeSubtree, strings.Replace.

func (*LDAPStorageHandler) GetKeys

func (l *LDAPStorageHandler) GetKeys(filter string) []string {
	log.Warning("Not implementated")
	s := []string{}

	return s
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*LDAPStorageHandler) GetKeysAndValues

func (l *LDAPStorageHandler) GetKeysAndValues() map[string]string {
	log.Warning("Not implementated")

	s := map[string]string{}
	return s
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*LDAPStorageHandler) GetKeysAndValuesWithFilter

func (l *LDAPStorageHandler) GetKeysAndValuesWithFilter(filter string) map[string]string {
	log.Warning("Not implementated")
	s := map[string]string{}
	return s
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*LDAPStorageHandler) GetListRange

func (l *LDAPStorageHandler) GetListRange(keyName string, from, to int64) ([]string, error) {
	log.Error("Not implemented")
	return nil, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) GetMultiKey

func (r *LDAPStorageHandler) GetMultiKey(keyNames []string) ([]string, error) {
	log.Warning("Not implementated")

	return nil, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) GetRawKey

func (l *LDAPStorageHandler) GetRawKey(filter string) (string, error) {
	log.Warning("Not implementated")

	return "", nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) GetRollingWindow

func (l *LDAPStorageHandler) GetRollingWindow(keyName string, per int64, pipeline bool) (int, []interface{}) {
	log.Warning("Not Implemented!")
	return 0, nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*LDAPStorageHandler) IncrememntWithExpire

func (l *LDAPStorageHandler) IncrememntWithExpire(keyName string, timeout int64) int64 {
	l.notifyReadOnly()
	return 999
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) LoadConfFromMeta

func (l *LDAPStorageHandler) LoadConfFromMeta(meta map[string]interface{}) {
	l.LDAPServer = meta["ldap_server"].(string)
	l.LDAPPort = uint16(meta["ldap_port"].(float64))
	l.BaseDN = meta["base_dn"].(string)

	attrArray := []string{}

	for _, attr := range meta["attributes"].([]interface{}) {
		val := attr.(string)
		attrArray = append(attrArray, val)
	}

	l.Attributes = attrArray
	l.SessionAttributeName = meta["session_attribute_name"].(string)
	l.SearchString = meta["search_string"].(string)

}

Cognitive complexity: 6, Cyclomatic complexity: 2

func (*LDAPStorageHandler) SetExp

func (l *LDAPStorageHandler) SetExp(cn string, exp int64) error {
	log.Warning("Not implementated")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) SetKey

func (l *LDAPStorageHandler) SetKey(cn, session string, timeout int64) error {
	l.notifyReadOnly()
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) SetRawKey

func (l *LDAPStorageHandler) SetRawKey(cn, session string, timeout int64) error {
	l.notifyReadOnly()
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*LDAPStorageHandler) SetRollingWindow

func (l *LDAPStorageHandler) SetRollingWindow(keyName string, per int64, val string, pipeline bool) (int, []interface{}) {
	log.Warning("Not Implemented!")
	return 0, nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*LogMessageEventHandler) HandleEvent

HandleEvent will be fired when the event handler instance is found in an APISpec EventPaths object during a request chain

func (l *LogMessageEventHandler) HandleEvent(em config.EventMessage) {
	logMsg := l.conf.Prefix + ":" + string(em.Type)

	logEventMessage, ok := em.Meta.(LogEventMessage)
	if ok {
		logMsg = logEventMessage.LogMessage(logMsg)
	}

	l.logger.Warning(logMsg)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*LogMessageEventHandler) Init

Init initializes the LogMessageEventHandler instance with the given configuration.

func (l *LogMessageEventHandler) Init(handlerConf any) error {
	var err error
	if err = l.conf.Scan(handlerConf); err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "log_event_handler",
		}).Error("Problem getting configuration, skipping. ", err)
		return err
	}

	if l.conf.Disabled {
		log.WithFields(logrus.Fields{
			"prefix": "log_event_handler",
		}).Infof("skipping disabled log event handler with prefix %s", l.conf.Prefix)
		return ErrEventHandlerDisabled
	}

	l.logger = log
	return nil
}

Cognitive complexity: 6, Cyclomatic complexity: 3

Uses: logrus.Fields.

func (*MiddlewareContextVars) EnabledForSpec

func (m *MiddlewareContextVars) EnabledForSpec() bool {
	return m.Spec.EnableContextVars
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*MiddlewareContextVars) Name

func (m *MiddlewareContextVars) Name() string {
	return "MiddlewareContextVars"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*MiddlewareContextVars) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (m *MiddlewareContextVars) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {

	parseForm(r)

	contextDataObject := map[string]interface{}{
		"request_data":	r.Form,	// Form params (map[string][]string)
		"headers":	map[string][]string(r.Header),
		"headers_Host":	r.Host,
		"path_parts":	strings.Split(r.URL.Path, "/"),	// Path parts
		"path":		r.URL.Path,			// path data
		"remote_addr":	request.RealIP(r),		// IP
		"request_id":	uuid.New(),			//Correlation ID
	}

	for hname, vals := range r.Header {
		n := "headers_" + strings.Replace(hname, "-", "_", -1)
		contextDataObject[n] = vals[0]
	}

	for _, c := range r.Cookies() {
		name := "cookies_" + strings.Replace(c.Name, "-", "_", -1)
		contextDataObject[name] = c.Value
	}

	for key, vals := range r.Form {
		name := "request_data_" + strings.Replace(key, "-", "_", -1)
		if len(vals) > 0 {
			contextDataObject[name] = vals[0]
		}
	}

	ctxSetData(r, contextDataObject)

	return nil, http.StatusOK
}

Cognitive complexity: 14, Cyclomatic complexity: 5

Uses: http.StatusOK, request.RealIP, strings.Replace, strings.Split, uuid.New.

func (*MiniRequestObject) ReconstructParams

func (mr *MiniRequestObject) ReconstructParams(r *http.Request) {
	updatedValues := r.URL.Query()

	for _, k := range mr.DeleteParams {
		updatedValues.Del(k)
	}

	for p, v := range mr.AddParams {
		updatedValues.Set(p, v)
	}

	for p, v := range mr.ExtendedParams {
		for _, val := range v {
			updatedValues.Add(p, val)
		}
	}

	if !reflect.DeepEqual(r.URL.Query(), updatedValues) {
		r.URL.RawQuery = updatedValues.Encode()
	}
}

Cognitive complexity: 14, Cyclomatic complexity: 6

Uses: reflect.DeepEqual.

func (*MockErrorReader) Read

func (e *MockErrorReader) Read(_ []byte) (n int, err error) {
	return 0, e.ReturnError
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*MockReadCloser) Close

func (m *MockReadCloser) Close() error {
	m.CloseCalled = true

	return m.CloseError
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*MockReadCloser) Read

func (m *MockReadCloser) Read(p []byte) (n int, err error) {
	return m.Reader.Read(p)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*MultiTargetProxy) CopyResponse

func (m *MultiTargetProxy) CopyResponse(dst io.Writer, src io.Reader, flushInterval time.Duration) {
	m.defaultProxy.CopyResponse(dst, src, flushInterval)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*MultiTargetProxy) ServeHTTP

func (m *MultiTargetProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) ProxyResponse {
	log.WithFields(logrus.Fields{
		"prefix": "multi-target",
	}).Debug("Serving Multi-target...")
	return m.proxyForRequest(r).ServeHTTP(w, r)
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: logrus.Fields.

func (*MultiTargetProxy) ServeHTTPForCache

func (m *MultiTargetProxy) ServeHTTPForCache(w http.ResponseWriter, r *http.Request) ProxyResponse {
	return m.proxyForRequest(r).ServeHTTPForCache(w, r)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Notification) Sign

func (n *Notification) Sign() {
	n.SignatureAlgo = crypto.SHA256
	hash := sha256.Sum256([]byte(string(n.Command) + n.Payload + n.Gw.GetConfig().NodeSecret))
	n.Signature = hex.EncodeToString(hash[:])
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: crypto.SHA256, hex.EncodeToString, sha256.Sum256.

func (*OAuthClient) GetDescription

func (oc *OAuthClient) GetDescription() string {
	return oc.Description
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*OAuthClient) GetId

func (oc *OAuthClient) GetId() string {
	return oc.ClientID
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*OAuthClient) GetPolicyID

func (oc *OAuthClient) GetPolicyID() string {
	return oc.PolicyID
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*OAuthClient) GetRedirectUri

func (oc *OAuthClient) GetRedirectUri() string {
	return oc.ClientRedirectURI
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*OAuthClient) GetSecret

func (oc *OAuthClient) GetSecret() string {
	return oc.ClientSecret
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*OAuthClient) GetUserData

func (oc *OAuthClient) GetUserData() interface{} {
	return oc.MetaData
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*OAuthHandlers) HandleAccessRequest

HandleAccessRequest handles the OAuth 2.0 token or refresh access request, and wraps Tyk's own and Osin's OAuth handlers, returns a response to the client and notifies the provider of the access request (in order to track identity against OAuth tokens without revealing tokens before they are requested).

func (o *OAuthHandlers) HandleAccessRequest(w http.ResponseWriter, r *http.Request) {
	w.Header().Set(header.ContentType, header.ApplicationJSON)
	// Handle response
	resp := o.Manager.HandleAccess(r)
	msg := o.generateOAuthOutputFromOsinResponse(resp)

	if resp.IsError {
		// Something went wrong, write out the error details and kill the response
		w.WriteHeader(resp.ErrorStatusCode)
		w.Write(msg)
		return
	}

	// Ping endpoint with o_auth key and auth_key
	authCode := r.FormValue("code")
	oldRefreshToken := r.FormValue("refresh_token")
	log.Debug("AUTH CODE: ", authCode)
	newOauthToken := ""
	if resp.Output["access_token"] != nil {
		newOauthToken = resp.Output["access_token"].(string)
	}
	log.Debug("TOKEN: ", newOauthToken)
	refreshToken := ""
	if resp.Output["refresh_token"] != nil {
		refreshToken = resp.Output["refresh_token"].(string)
	}
	log.Debug("REFRESH: ", refreshToken)
	log.Debug("Old REFRESH: ", oldRefreshToken)

	notificationType := newAccessToken
	if oldRefreshToken != "" {
		notificationType = refreshAccessToken
	}

	newNotification := NewOAuthNotification{
		AuthCode:		authCode,
		NewOAuthToken:		newOauthToken,
		RefreshToken:		refreshToken,
		OldRefreshToken:	oldRefreshToken,
		NotificationType:	notificationType,
	}

	o.notifyClientOfNewOauth(newNotification)

	w.WriteHeader(http.StatusOK)
	w.Write(msg)
}

Cognitive complexity: 9, Cyclomatic complexity: 5

Uses: header.ApplicationJSON, header.ContentType, http.StatusOK.

func (*OAuthHandlers) HandleAuthorizePassthrough

HandleAuthorizePassthrough handles a Client Auth request, first it checks if the client is OK (otherwise it blocks the request), then it forwards on to the resource providers approval URI

func (o *OAuthHandlers) HandleAuthorizePassthrough(w http.ResponseWriter, r *http.Request) {
	// Extract client data and check
	resp := o.Manager.HandleAuthorisation(r, false, "")
	if resp.IsError {
		log.Error("[OAuth] There was an error with the request: ", resp)
		// Something went wrong, write out the error details and kill the response
		doJSONWrite(w, resp.ErrorStatusCode, apiError(resp.StatusText))
		return
	}
	if r.Method == "GET" {
		loginURL := fmt.Sprintf("%s?%s", o.Manager.API.Oauth2Meta.AuthorizeLoginRedirect, r.URL.RawQuery)
		w.Header().Add("Location", loginURL)
	} else {
		w.Header().Add("Location", o.Manager.API.Oauth2Meta.AuthorizeLoginRedirect)
	}
	w.WriteHeader(307)

}

Cognitive complexity: 6, Cyclomatic complexity: 3

Uses: fmt.Sprintf.

func (*OAuthHandlers) HandleGenerateAuthCodeData

HandleGenerateAuthCodeData handles a resource provider approving an OAuth request from a client

func (o *OAuthHandlers) HandleGenerateAuthCodeData(w http.ResponseWriter, r *http.Request) {
	// On AUTH grab session state data and add to UserData (not validated, not good!)
	sessionJSONData := r.FormValue("key_rules")
	if sessionJSONData == "" {
		log.Warning("Authorise request is missing key_rules in params, policy will be required!")
	}

	// Handle the authorisation and write the JSON output to the resource provider
	resp := o.Manager.HandleAuthorisation(r, true, sessionJSONData)
	code := http.StatusOK
	msg := o.generateOAuthOutputFromOsinResponse(resp)

	if resp.IsError {
		code = resp.ErrorStatusCode
		log.Error("[OAuth] OAuth response marked as error: ", resp)
	}
	w.WriteHeader(code)
	w.Write(msg)
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: http.StatusOK.

func (*OAuthHandlers) HandleRevokeAllTokens

func (o *OAuthHandlers) HandleRevokeAllTokens(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		doJSONWrite(w, http.StatusBadRequest, apiError("error parsing form. Form malformed"))
		return
	}

	clientId := r.PostFormValue("client_id")
	secret := r.PostFormValue("client_secret")

	if clientId == "" {
		doJSONWrite(w, http.StatusUnauthorized, apiError(oauthClientIdEmpty))
		return
	}

	if secret == "" {
		doJSONWrite(w, http.StatusUnauthorized, apiError(oauthClientSecretEmpty))
		return
	}

	status, tokens, err := RevokeAllTokens(o.Manager.OsinServer.Storage, clientId, secret)
	if err != nil {
		doJSONWrite(w, status, apiError(err.Error()))
		return
	}

	n := Notification{
		Command:	KeySpaceUpdateNotification,
		Payload:	strings.Join(tokens, ","),
		Gw:		o.Manager.Gw,
	}
	o.Manager.Gw.MainNotifier.Notify(n)

	doJSONWrite(w, http.StatusOK, apiOk("tokens revoked successfully"))
}

Cognitive complexity: 9, Cyclomatic complexity: 5

Uses: http.StatusBadRequest, http.StatusOK, http.StatusUnauthorized, strings.Join.

func (*OAuthHandlers) HandleRevokeToken

in compliance with https://tools.ietf.org/html/rfc7009#section-2.1 ToDo: set an authentication mechanism

func (o *OAuthHandlers) HandleRevokeToken(w http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	if err != nil {
		doJSONWrite(w, http.StatusBadRequest, apiError("error parsing form. Form malformed"))
		return
	}

	token := r.PostFormValue("token")
	tokenTypeHint := r.PostFormValue("token_type_hint")

	if token == "" {
		doJSONWrite(w, http.StatusBadRequest, apiError(oauthTokenEmpty))
		return
	}

	RevokeToken(o.Manager.OsinServer.Storage, token, tokenTypeHint)
	doJSONWrite(w, http.StatusOK, apiOk("token revoked successfully"))
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: http.StatusBadRequest, http.StatusOK.

func (*OAuthManager) HandleAccess

HandleAccess wraps an access request with osin's primitives

func (o *OAuthManager) HandleAccess(r *http.Request) *osin.Response {
	resp := o.OsinServer.NewResponse()
	// we are intentionally ignoring errors, because this is called again by
	// osin.We are only doing this to ensure r.From is properly initialized incase
	// r.ParseForm was success
	r.ParseForm()
	if err := JSONToFormValues(r); err != nil {
		log.Errorf("trying to set url values decoded from json body :%v", err)
	}
	var username string

	if ar := o.OsinServer.HandleAccessRequest(resp, r); ar != nil {

		var session *user.SessionState
		if ar.Type == osin.PASSWORD {
			username = r.Form.Get("username")
			password := r.Form.Get("password")
			searchKey := "apikey-" + storage.HashKey(o.API.OrgID+username, o.Gw.GetConfig().HashKeys)
			log.Debug("Getting: ", searchKey)

			var err error
			session, err = o.OsinServer.Storage.GetUser(searchKey)
			if err != nil {
				log.Warning("Attempted access with non-existent user (OAuth password flow).")
			} else {
				var passMatch bool
				if session.BasicAuthData.Hash == user.HashBCrypt {
					err := bcrypt.CompareHashAndPassword([]byte(session.BasicAuthData.Password), []byte(password))
					if err == nil {
						passMatch = true
					}
				}

				if session.BasicAuthData.Hash == user.HashPlainText &&
					session.BasicAuthData.Password == password {
					passMatch = true
				}

				if passMatch {
					ar.Authorized = true
					// not ideal, but we need to copy the session state across
					pw := session.BasicAuthData.Password
					hs := session.BasicAuthData.Hash

					session.BasicAuthData.Password = ""
					session.BasicAuthData.Hash = ""
					asString, _ := json.Marshal(session)
					ar.UserData = string(asString)

					session.BasicAuthData.Password = pw
					session.BasicAuthData.Hash = hs

					//log.Warning("Old Keys: ", session.OauthKeys)
				}
			}
		} else {
			// Using a manual flow
			ar.Authorized = true
		}

		// Does the user have an old OAuth token for this client?
		if session != nil && session.OauthKeys != nil {
			log.Debug("There's keys here bill...")
			oldToken, foundKey := session.OauthKeys[ar.Client.GetId()]
			if foundKey {
				log.Info("Found old token, revoking: ", oldToken)
				o.Gw.GlobalSessionManager.RemoveSession(o.API.OrgID, oldToken, false)
			}
		}

		log.Debug("[OAuth] Finishing access request ")
		o.OsinServer.FinishAccessRequest(resp, r, ar)
		new_token, foundNewToken := resp.Output["access_token"]
		if username != "" && foundNewToken {
			log.Debug("Updating token data in key")
			if session.OauthKeys == nil {
				session.OauthKeys = make(map[string]string)
			}
			session.OauthKeys[ar.Client.GetId()] = new_token.(string)
			log.Debug("New token: ", new_token.(string))
			log.Debug("Keys: ", session.OauthKeys)

			// add oauth-client user_fields to session's meta
			if userData := ar.Client.GetUserData(); userData != nil {
				metadata, ok := userData.(map[string]interface{})
				if !ok {
					log.WithField("oauthClientID", ar.Client.GetId()).
						Error("Could not set session meta_data from oauth-client fields, type mismatch")
				} else {
					session.MetaData = metadata
					// set session alias to developer email as we do it for regular API keys created for developer
					if devEmail, found := session.MetaData[keyDataDeveloperEmail].(string); found {
						session.Alias = devEmail
						// we don't need it in meta-data as we set it to alias
						delete(session.MetaData, keyDataDeveloperEmail)
					}
				}
			}

			keyName := o.Gw.generateToken(o.API.OrgID, username)

			log.Debug("Updating user:", keyName)
			err := o.Gw.GlobalSessionManager.UpdateSession(keyName, session, session.Lifetime(o.API.GetSessionLifetimeRespectsKeyExpiration(), o.API.SessionLifetime, o.Gw.GetConfig().ForceGlobalSessionLifetime, o.Gw.GetConfig().GlobalSessionLifetime), false)
			if err != nil {
				log.Error(err)
			}
		}
	}
	if resp.IsError {
		clientId := r.Form.Get("client_id")
		log.WithFields(logrus.Fields{
			"org_id":		o.API.OrgID,
			"client_id":		clientId,
			"response error":	resp.StatusText,
			"response code":	resp.ErrorStatusCode,
			"RemoteAddr":		request.RealIP(r),	//r.RemoteAddr,
		}).Error("[OAuth] OAuth response marked as error")
	}

	return resp
}

Cognitive complexity: 42, Cyclomatic complexity: 21

Uses: bcrypt.CompareHashAndPassword, json.Marshal, logrus.Fields, osin.PASSWORD, request.RealIP, storage.HashKey, user.HashBCrypt, user.HashPlainText, user.SessionState.

func (*OAuthManager) HandleAuthorisation

HandleAuthorisation creates the authorisation data for the request

func (o *OAuthManager) HandleAuthorisation(r *http.Request, complete bool, session string) *osin.Response {
	resp := o.OsinServer.NewResponse()

	if ar := o.OsinServer.HandleAuthorizeRequest(resp, r); ar != nil {
		// Since this is called by the Reource provider (proxied API), we assume it has been approved
		ar.Authorized = true

		if complete {
			ar.UserData = session
			o.OsinServer.FinishAuthorizeRequest(resp, r, ar)
		}
	}
	if resp.IsError && resp.InternalError != nil {
		log.Error(resp.InternalError)
	}

	return resp
}

Cognitive complexity: 6, Cyclomatic complexity: 5

func (*OAuthManager) Storage

func (o *OAuthManager) Storage() ExtendedOsinStorageInterface {
	return o.OsinServer.Storage
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Oauth2KeyExists) EnabledForSpec

func (k *Oauth2KeyExists) EnabledForSpec() bool {
	return k.Spec.UseOauth2
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Oauth2KeyExists) Name

func (k *Oauth2KeyExists) Name() string {
	return "Oauth2KeyExists"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Oauth2KeyExists) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (k *Oauth2KeyExists) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	logger := k.Logger()
	// We're using OAuth, start checking for access keys
	token, _ := k.getAuthToken(k.getAuthType(), r)
	parts := strings.Split(token, " ")

	if len(parts) < 2 {
		logger.Info("Attempted access with malformed header, no auth header found.")

		return errorAndStatusCode(ErrOAuthAuthorizationFieldMissing)
	}

	if strings.ToLower(parts[0]) != "bearer" {
		logger.Info("Bearer token malformed")

		return errorAndStatusCode(ErrOAuthAuthorizationFieldMalformed)
	}

	accessToken := parts[1]
	logger = logger.WithField("key", k.Gw.obfuscateKey(accessToken))

	// get session for the given oauth token
	session, keyExists := k.CheckSessionAndIdentityForValidKey(accessToken, r)
	accessToken = session.KeyID

	if !keyExists {
		logger.Warning("Attempted access with non-existent key.")

		// Fire Authfailed Event
		AuthFailed(k, r, accessToken)
		// Report in health check
		reportHealthValue(k.Spec, KeyFailure, "-1")

		return errorAndStatusCode(ErrOAuthKeyNotFound)
	}

	// Make sure OAuth-client is still present
	oauthClientDeletedKey := "oauth-del-" + k.Spec.APIID + session.OauthClientID
	oauthClientDeleted := false
	// check if that oauth client was deleted with using  memory cache first
	if val, found := k.Gw.UtilCache.Get(oauthClientDeletedKey); found {
		oauthClientDeleted = val.(bool)
	} else {
		// if not cached in memory then hit Redis to get oauth-client from there
		if _, err := k.Spec.OAuthManager.Storage().GetClient(session.OauthClientID); err != nil {
			// set this oauth client as deleted in memory cache for the next N sec
			k.Gw.UtilCache.Set(oauthClientDeletedKey, true, checkOAuthClientDeletedInterval)
			oauthClientDeleted = true
		} else {
			// set this oauth client as NOT deleted in memory cache for next N sec
			k.Gw.UtilCache.Set(oauthClientDeletedKey, false, checkOAuthClientDeletedInterval)
		}
	}
	if oauthClientDeleted {
		logger.WithField("oauthClientID", session.OauthClientID).Warning("Attempted access for deleted OAuth client.")
		return errorAndStatusCode(ErrOAuthClientDeleted)
	}

	// Set session state on context, we will need it later
	switch k.Spec.BaseIdentityProvidedBy {
	case apidef.OAuthKey, apidef.UnsetAuth:
		hashKeys := k.Gw.GetConfig().HashKeys
		ctxSetSession(r, &session, false, hashKeys)
		if hashKeys {
			ctxSetSpanAttributes(r, k.Name(), otel.OAuthClientIDAttribute(session.KeyHash()))
		}
	}

	// Request is valid, carry on
	return nil, http.StatusOK
}

Cognitive complexity: 24, Cyclomatic complexity: 11

Uses: apidef.OAuthKey, apidef.UnsetAuth, http.StatusOK, otel.OAuthClientIDAttribute, strings.Split, strings.ToLower.

func (*OpenIDMW) EnabledForSpec

func (k *OpenIDMW) EnabledForSpec() bool {
	if k.Spec.UseOpenID {
		log.Warn("Support for OpenID Connect Middleware will be deprecated starting from 5.7.0. To avoid any disruptions, we recommend that you use JSON Web Token (JWT) instead, as explained in https://tyk.io/docs/basic-config-and-security/security/authentication-authorization/openid-connect/")
	}

	return k.Spec.UseOpenID
}

Cognitive complexity: 3, Cyclomatic complexity: 3

func (*OpenIDMW) Init

func (k *OpenIDMW) Init() {
	k.provider_client_policymap = make(map[string]map[string]string)
	// Create an OpenID Configuration and store
	var err error
	k.providerConfiguration, err = openid.NewConfiguration(openid.ProvidersGetter(k.getProviders),
		openid.ErrorHandler(k.dummyErrorHandler))

	if err != nil {
		k.Logger().WithError(err).Error("OpenID configuration error")
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: openid.ErrorHandler, openid.NewConfiguration, openid.ProvidersGetter.

func (*OpenIDMW) Name

func (k *OpenIDMW) Name() string {
	return "OpenIDMW"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*OpenIDMW) ProcessRequest

func (k *OpenIDMW) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	k.providerConfiguration.IDTokenGetter = func(r *http.Request) (token string, err error) {
		token, _ = k.getAuthToken(k.getAuthType(), r)
		return openid.CheckAndSplitHeader(token)
	}

	logger := k.Logger()
	// 1. Validate the JWT
	ouser, token, halt := openid.AuthenticateOIDWithUser(k.providerConfiguration, w, r)

	// 2. Generate the internal representation for the key
	if halt {
		// Fire Authfailed Event
		k.reportLoginFailure("[JWT]", r)
		return errors.New("Key not authorised"), http.StatusUnauthorized
	}

	// 3. Create or set the session to match
	iss, found := token.Claims.(jwt.MapClaims)["iss"]
	clients, cfound := token.Claims.(jwt.MapClaims)["aud"]

	if !found && !cfound {
		logger.Error("No issuer or audiences found!")
		k.reportLoginFailure("[NOT GENERATED]", r)
		return errors.New("Key not authorised"), http.StatusUnauthorized
	}

	// decide if we use policy ID from provider client settings or list of policies from scope-policy mapping
	useScope := len(k.Spec.GetScopeToPolicyMapping()) != 0

	k.lock.RLock()
	clientSet, foundIssuer := k.provider_client_policymap[iss.(string)]
	k.lock.RUnlock()
	if !foundIssuer {
		logger.Error("No issuer or audiences found!")
		k.reportLoginFailure("[NOT GENERATED]", r)
		return errors.New("Key not authorised"), http.StatusUnauthorized
	}

	policyID := ""
	clientID := ""
	switch v := clients.(type) {
	case string:
		k.lock.RLock()
		policyID = clientSet[v]
		k.lock.RUnlock()
		clientID = v
	case []interface{}:
		for _, audVal := range v {
			k.lock.RLock()
			policy, foundPolicy := clientSet[audVal.(string)]
			k.lock.RUnlock()
			if foundPolicy {
				clientID = audVal.(string)
				policyID = policy
				break
			}
		}
	}

	if !useScope && policyID == "" {
		logger.Error("No matching policy found!")
		k.reportLoginFailure("[NOT GENERATED]", r)
		return errors.New("Key not authorised"), http.StatusUnauthorized
	}

	data := []byte(ouser.ID)
	keyID := fmt.Sprintf("%x", md5.Sum(data))
	sessionID := k.Gw.generateToken(k.Spec.OrgID, keyID)

	if k.Spec.OpenIDOptions.SegregateByClient {
		// We are segregating by client, so use it as part of the internal token
		logger.Debug("Client ID:", clientID)
		sessionID = k.Gw.generateToken(k.Spec.OrgID, fmt.Sprintf("%x", md5.Sum([]byte(clientID)))+keyID)
	}

	logger.Debug("Generated Session ID: ", sessionID)

	var policiesToApply []string
	if !useScope {
		policiesToApply = append(policiesToApply, policyID)
	} else {
		scopeClaimName := k.Spec.GetScopeClaimName()
		if scopeClaimName == "" {
			scopeClaimName = "scope"
		}

		if scope := getScopeFromClaim(token.Claims.(jwt.MapClaims), scopeClaimName); scope != nil {
			// add all policies matched from scope-policy mapping
			policiesToApply = mapScopeToPolicies(k.Spec.GetScopeToPolicyMapping(), scope)
		}
	}

	session, exists := k.CheckSessionAndIdentityForValidKey(sessionID, r)
	sessionID = session.KeyID
	if !exists {
		// Create it
		logger.Debug("Key does not exist, creating")
		session = user.SessionState{}

		if !useScope {
			// We need a base policy as a template, either get it from the token itself OR a proxy client ID within Tyk
			newSession, err := k.Gw.generateSessionFromPolicy(policyID,
				k.Spec.OrgID,
				true)

			if err != nil {
				k.reportLoginFailure(sessionID, r)
				logger.Error("Could not find a valid policy to apply to this token!")
				return errors.New("Key not authorized: no matching policy"), http.StatusForbidden
			}

			session = newSession.Clone()
		}

		session.OrgID = k.Spec.OrgID
		session.MetaData = map[string]interface{}{"TykJWTSessionID": sessionID, "ClientID": clientID}
		session.Alias = clientID + ":" + ouser.ID
		session.KeyID = sessionID

		// Update the session in the session manager in case it gets called again
		logger.Debug("Policy applied to key")
	}
	// apply new policy to session if any and update session
	session.SetPolicies(policiesToApply...)
	if err := k.ApplyPolicies(&session); err != nil {
		k.Logger().WithError(err).Error("Could not apply new policy from OIDC client to session")
		return errors.New("Key not authorized: could not apply new policy"), http.StatusForbidden
	}

	// 4. Set session state on context, we will need it later
	switch k.Spec.BaseIdentityProvidedBy {
	case apidef.OIDCUser, apidef.UnsetAuth:
		ctxSetSession(r, &session, true, k.Gw.GetConfig().HashKeys)
	}
	ctxSetJWTContextVars(k.Spec, r, token)

	return nil, http.StatusOK
}

Cognitive complexity: 46, Cyclomatic complexity: 23

Uses: apidef.OIDCUser, apidef.UnsetAuth, errors.New, fmt.Sprintf, http.Request, http.StatusForbidden, http.StatusOK, http.StatusUnauthorized, md5.Sum, openid.AuthenticateOIDWithUser, openid.CheckAndSplitHeader, user.SessionState.

func (*OrganizationMonitor) AllowAccessNext

func (k *OrganizationMonitor) AllowAccessNext(
	orgChan chan bool,
	path string,
	IP string,
	r *http.Request,
	session *user.SessionState) {

	// Is it active?
	logEntry := k.Gw.getExplicitLogEntryForRequest(k.Logger(), path, IP, k.Spec.OrgID, nil)
	if session.IsInactive {
		logEntry.Warning("Organisation access is disabled.")
		orgChan <- false
		return
	}

	customQuotaKey := ""

	// We found a session, apply the quota and rate limiter
	reason := k.Gw.SessionLimiter.ForwardMessage(
		r,
		session,
		k.Spec.OrgID,
		customQuotaKey,
		k.Spec.OrgSessionManager.Store(),
		session.Per > 0 && session.Rate > 0,
		true,
		k.Spec,
		false,
	)

	sessionLifeTime := session.Lifetime(k.Spec.GetSessionLifetimeRespectsKeyExpiration(), k.Spec.SessionLifetime, k.Gw.GetConfig().ForceGlobalSessionLifetime, k.Gw.GetConfig().GlobalSessionLifetime)

	if err := k.Spec.OrgSessionManager.UpdateSession(k.Spec.OrgID, session, sessionLifeTime, false); err == nil {
		// update in-app cache if needed
		if !k.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
			k.Gw.SessionCache.Set(k.Spec.OrgID, session.Clone(), sessionLifeTime)
		}
	} else {
		logEntry.WithError(err).WithField("orgID", k.Spec.OrgID).Error("Could not update org session")
	}

	isExceeded := false
	switch reason {
	case sessionFailNone:
		// all good, keep org active
	case sessionFailQuota:
		isExceeded = true

		logEntry.Warning("Organisation quota has been exceeded.")

		// Fire a quota exceeded event
		k.FireEvent(
			EventOrgQuotaExceeded,
			EventKeyFailureMeta{
				EventMetaDefault: EventMetaDefault{
					Message: "Organisation quota has been exceeded",
				},
				Path:	path,
				Origin:	IP,
				Key:	k.Spec.OrgID,
			},
		)
	case sessionFailRateLimit:
		isExceeded = true

		logEntry.Warning("Organisation rate limit has been exceeded.")

		// Fire a rate limit exceeded event
		k.FireEvent(
			EventOrgRateLimitExceeded,
			EventKeyFailureMeta{
				EventMetaDefault: EventMetaDefault{
					Message: "Organisation rate limit has been exceeded",
				},
				Path:	path,
				Origin:	IP,
				Key:	k.Spec.OrgID,
			},
		)
	}

	if k.Spec.GlobalConfig.Monitor.MonitorOrgKeys {
		// Run the trigger monitor
		k.mon.Check(session, "")
	}

	if isExceeded {
		orgChan <- false
		return
	}

	orgChan <- true
}

Cognitive complexity: 21, Cyclomatic complexity: 11

func (*OrganizationMonitor) EnabledForSpec

func (k *OrganizationMonitor) EnabledForSpec() bool {
	// If false, we aren't enforcing quotas so skip this mw
	// altogether
	return k.Spec.GlobalConfig.EnforceOrgQuotas
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*OrganizationMonitor) Name

func (k *OrganizationMonitor) Name() string {
	return "OrganizationMonitor"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*OrganizationMonitor) ProcessRequest

func (k *OrganizationMonitor) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	// Skip rate limiting and quotas for looping
	if !ctxCheckLimits(r) {
		return nil, http.StatusOK
	}

	// short path for specs which have organization limiter enabled but organization has no session
	if k.getOrgHasNoSession() {
		return nil, http.StatusOK
	}

	var orgSession user.SessionState
	var found bool

	// try to check in in-app cache 1st
	if !k.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
		var cachedSession interface{}
		if cachedSession, found = k.Gw.SessionCache.Get(k.Spec.OrgID); found {
			sess := cachedSession.(user.SessionState)
			orgSession = sess.Clone()
		}
	}

	// try to get from Redis
	if !found {
		// not found in in-app cache, let's read from Redis
		orgSession, found = k.OrgSession(k.Spec.OrgID)
		if !found {
			// prevent reads from in-app cache and from Redis for next runs
			k.setOrgHasNoSession(true)
			// No organisation session has not been created, should not be a pre-requisite in site setups, so we pass the request on
			return nil, http.StatusOK
		}
	}
	clone := orgSession.Clone()
	if k.Spec.GlobalConfig.ExperimentalProcessOrgOffThread {
		// Make a copy of request before before sending to goroutine
		r2 := r.WithContext(r.Context())
		return k.ProcessRequestOffThread(r2, &clone)
	}
	return k.ProcessRequestLive(r, &clone)
}

Cognitive complexity: 16, Cyclomatic complexity: 8

Uses: http.StatusOK, user.SessionState.

func (*OrganizationMonitor) ProcessRequestLive

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (k *OrganizationMonitor) ProcessRequestLive(r *http.Request, orgSession *user.SessionState) (error, int) {
	logger := k.Logger()

	if orgSession.IsInactive {
		logger.Warning("Organisation access is disabled.")

		return errors.New("this organisation access has been disabled, please contact your API administrator"), http.StatusForbidden
	}

	customQuotaKey := ""

	// We found a session, apply the quota and rate limiter
	reason := k.Gw.SessionLimiter.ForwardMessage(
		r,
		orgSession,
		k.Spec.OrgID,
		customQuotaKey,
		k.Spec.OrgSessionManager.Store(),
		orgSession.Per > 0 && orgSession.Rate > 0,
		true,
		k.Spec,
		false,
	)

	sessionLifeTime := orgSession.Lifetime(k.Spec.GetSessionLifetimeRespectsKeyExpiration(), k.Spec.SessionLifetime, k.Gw.GetConfig().ForceGlobalSessionLifetime, k.Gw.GetConfig().GlobalSessionLifetime)

	if err := k.Spec.OrgSessionManager.UpdateSession(k.Spec.OrgID, orgSession, sessionLifeTime, false); err == nil {
		// update in-app cache if needed
		if !k.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
			k.Gw.SessionCache.Set(k.Spec.OrgID, orgSession.Clone(), sessionLifeTime)
		}
	} else {
		logger.WithError(err).Error("Could not update org session")
	}

	switch reason {
	case sessionFailNone:
		// all good, keep org active
	case sessionFailQuota:
		logger.Warning("Organisation quota has been exceeded.", k.Spec.OrgID)

		// Fire a quota exceeded event
		k.FireEvent(
			EventOrgQuotaExceeded,
			EventKeyFailureMeta{
				EventMetaDefault: EventMetaDefault{
					Message:		"Organisation quota has been exceeded",
					OriginatingRequest:	EncodeRequestToEvent(r),
				},
				Path:	r.URL.Path,
				Origin:	request.RealIP(r),
				Key:	k.Spec.OrgID,
			})

		return errors.New("This organisation quota has been exceeded, please contact your API administrator"), http.StatusForbidden
	case sessionFailRateLimit:
		logger.Warning("Organisation rate limit has been exceeded.", k.Spec.OrgID)

		// Fire a rate limit exceeded event
		k.FireEvent(
			EventOrgRateLimitExceeded,
			EventKeyFailureMeta{
				EventMetaDefault: EventMetaDefault{
					Message:		"Organisation rate limit has been exceeded",
					OriginatingRequest:	EncodeRequestToEvent(r),
				},
				Path:	r.URL.Path,
				Origin:	request.RealIP(r),
				Key:	k.Spec.OrgID,
			},
		)
		return errors.New("This organisation rate limit has been exceeded, please contact your API administrator"), http.StatusForbidden
	}

	if k.Spec.GlobalConfig.Monitor.MonitorOrgKeys {
		// Run the trigger monitor
		k.mon.Check(orgSession, "")
	}

	// Lets keep a reference of the org
	setCtxValue(r, ctx.OrgSessionContext, orgSession)

	// Request is valid, carry on
	return nil, http.StatusOK
}

Cognitive complexity: 19, Cyclomatic complexity: 10

Uses: ctx.OrgSessionContext, errors.New, http.StatusForbidden, http.StatusOK, request.RealIP.

func (*OrganizationMonitor) ProcessRequestOffThread

func (k *OrganizationMonitor) ProcessRequestOffThread(r *http.Request, orgSession *user.SessionState) (error, int) {
	orgChanMap.Lock()
	orgChan, ok := orgChanMap.channels[k.Spec.OrgID]
	if !ok {
		orgChan = make(chan bool)
		orgChanMap.channels[k.Spec.OrgID] = orgChan
		go k.SetOrgSentinel(orgChan, k.Spec.OrgID)
	}
	orgChanMap.Unlock()
	active, found := orgActiveMap.Load(k.Spec.OrgID)

	// Lets keep a reference of the org
	// session might be updated by go-routine AllowAccessNext and we loose those changes here
	// but it is OK as we need it in context for detailed org logging
	clone := orgSession.Clone()
	setCtxValue(r, ctx.OrgSessionContext, &clone)

	orgSessionCopy := orgSession.Clone()
	go k.AllowAccessNext(
		orgChan,
		r.URL.Path,
		request.RealIP(r),
		r,
		&orgSessionCopy,
	)

	if found && !active.(bool) {
		k.Logger().Debug("Is not active")
		return errors.New("This organization access has been disabled or quota/rate limit is exceeded, please contact your API administrator"), http.StatusForbidden
	}

	// Request is valid, carry on
	return nil, http.StatusOK
}

Cognitive complexity: 4, Cyclomatic complexity: 4

Uses: ctx.OrgSessionContext, errors.New, http.StatusForbidden, http.StatusOK, request.RealIP.

func (*OrganizationMonitor) SetOrgSentinel

func (k *OrganizationMonitor) SetOrgSentinel(orgChan chan bool, orgId string) {
	for isActive := range orgChan {
		k.Logger().Debug("Chan got:", isActive)
		orgActiveMap.Store(orgId, isActive)
	}
}

Cognitive complexity: 3, Cyclomatic complexity: 2

func (*PersistGraphQLOperationMiddleware) EnabledForSpec

func (i *PersistGraphQLOperationMiddleware) EnabledForSpec() bool {
	for _, v := range i.Spec.VersionData.Versions {
		if len(v.ExtendedPaths.PersistGraphQL) > 0 {
			return true
		}
	}

	return false
}

Cognitive complexity: 5, Cyclomatic complexity: 3

func (*PersistGraphQLOperationMiddleware) Name

func (i *PersistGraphQLOperationMiddleware) Name() string {
	return "PersistGraphQLOperationMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*PersistGraphQLOperationMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (i *PersistGraphQLOperationMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	vInfo, _ := i.Spec.Version(r)
	versionPaths := i.Spec.RxPaths[vInfo.Name]
	found, meta := i.Spec.CheckSpecMatchesStatus(r, versionPaths, PersistGraphQL)
	if !found {
		// PersistGraphQLOperationMiddleware not enabled for this endpoint
		return nil, http.StatusOK
	}
	mwSpec, _ := meta.(*apidef.PersistGraphQLMeta)

	ctxSetRequestMethod(r, r.Method)
	r.Method = http.MethodPost

	_, err := io.ReadAll(r.Body)
	if err != nil {
		i.Logger().WithError(err).Error("error reading request")
		return errors.New("error reading the request"), http.StatusBadRequest
	}
	defer r.Body.Close()

	replacers := make(map[string]int)
	fullPath := fmt.Sprintf("%s/%s", strings.TrimRight(i.Spec.Proxy.ListenPath, "/"), strings.TrimLeft(mwSpec.Path, "/"))
	paths := strings.Split(fullPath, "/")
	for i, part := range paths {
		if strings.HasPrefix(part, "{") && strings.HasSuffix(part, "}") {
			key := "$path." + strings.Replace(part, "{", "", -1)
			key = strings.Replace(key, "}", "", -1)
			replacers[key] = i
		}
	}

	varBytes, err := json.Marshal(mwSpec.Variables)
	if err != nil {
		i.Logger().WithError(err).Error("error proxying request")
		return ProxyingRequestFailedErr, http.StatusInternalServerError
	}

	variablesStr := i.Gw.ReplaceTykVariables(r, string(varBytes), false)

	requestPathParts := strings.Split(r.RequestURI, "/")
	for replacer, pathIndex := range replacers {
		variablesStr = strings.ReplaceAll(variablesStr, replacer, requestPathParts[pathIndex])
	}

	graphqlQuery := GraphQLRequest{
		Query:		mwSpec.Operation,
		Variables:	[]byte(variablesStr),
	}

	graphQLQueryBytes, err := json.Marshal(graphqlQuery)
	if err != nil {
		i.Logger().WithError(err).Error("error proxying request")
		return ProxyingRequestFailedErr, http.StatusInternalServerError
	}
	newBuf := bytes.NewBuffer(graphQLQueryBytes)

	r.Body = io.NopCloser(newBuf)
	r.ContentLength = int64(newBuf.Len())
	nopCloseRequestBody(r)

	r.Header.Set("Content-Type", "application/json")

	ctxSetUrlRewritePath(r, r.URL.Path)
	r.URL.Path = "/"

	return nil, http.StatusOK
}

Cognitive complexity: 18, Cyclomatic complexity: 9

Uses: apidef.PersistGraphQLMeta, bytes.NewBuffer, errors.New, fmt.Sprintf, http.MethodPost, http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, io.NopCloser, io.ReadAll, json.Marshal, strings.HasPrefix, strings.HasSuffix, strings.Replace, strings.ReplaceAll, strings.Split, strings.TrimLeft, strings.TrimRight.

func (*RPCStorageHandler) AddToSortedSet

func (r *RPCStorageHandler) AddToSortedSet(keyName, value string, score float64) {
	r.Gw.handleGlobalAddToSortedSet(keyName, value, score)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) AppendToSet

func (r *RPCStorageHandler) AppendToSet(keyName, value string) {
	ibd := model.InboundData{
		KeyName:	keyName,
		Value:		value,
	}

	_, err := rpc.FuncClientSingleton("AppendToSet", ibd)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"AppendToSet",
			err,
			map[string]string{
				"keyName": keyName,
			},
		)
	}
	if r.IsRetriableError(err) {
		if rpc.Login() {
			r.AppendToSet(keyName, value)
		}
	}
}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: model.InboundData, rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) CheckForKeyspaceChanges

CheckForKeyspaceChanges will poll for keysace changes

func (r *RPCStorageHandler) CheckForKeyspaceChanges(orgId string) {
	log.Debug("Checking for keyspace changes...")

	var keys interface{}
	var err error
	var funcName string
	var req interface{}

	reqData := map[string]string{}
	if groupID := r.Gw.GetConfig().SlaveOptions.GroupID; groupID == "" {
		funcName = "GetKeySpaceUpdate"
		req = orgId
		reqData["orgId"] = orgId
	} else {
		funcName = "GetGroupKeySpaceUpdate"
		req = model.GroupKeySpaceRequest{
			OrgID:		orgId,
			GroupID:	groupID,
		}
		reqData["orgId"] = orgId
		reqData["GroupID"] = groupID
	}

	keys, err = rpc.FuncClientSingleton(funcName, req)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			funcName,
			err,
			reqData,
		)
		if r.IsRetriableError(err) {
			if rpc.Login() {
				r.CheckForKeyspaceChanges(orgId)
			}
		}
		log.Warning("Keyspace warning: ", err)
		return
	}

	if keys == nil {
		log.Info("Keys returned nil object, skipping check")
		return
	}

	if len(keys.([]string)) > 0 {
		log.Info("Keyspace changes detected, updating local cache")
		go r.ProcessKeySpaceChanges(keys.([]string), orgId)
	}
}

Cognitive complexity: 18, Cyclomatic complexity: 7

Uses: model.GroupKeySpaceRequest, rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) CheckForReload

CheckForReload will start a long poll

func (r *RPCStorageHandler) CheckForReload(orgId string) bool {
	select {
	case <-r.Gw.ctx.Done():
		return false
	default:
	}

	log.Debug("[RPC STORE] Check Reload called...")
	reload, err := rpc.FuncClientSingleton("CheckReload", orgId)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"CheckReload",
			err,
			map[string]string{
				"orgId": orgId,
			},
		)
		if r.IsRetriableError(err) {
			log.Warning("[RPC STORE] CheckReload: Not logged in")
			if rpc.Login() {
				r.CheckForReload(orgId)
			}
		} else if !strings.Contains(err.Error(), "Cannot obtain response during") {
			forcer := rpc.NewSyncForcer(r.Gw.StorageConnectionHandler, r.buildNodeInfo)
			forcer.SetFirstConnection(true)
			log.Warning("[RPC STORE] RPC Reload Checker encountered unexpected error: ", err)
		}

		time.Sleep(1 * time.Second)
	} else if reload == true {
		// Do the reload!
		log.Warning("[RPC STORE] Received Reload instruction!")
		go func() {
			r.Gw.MainNotifier.Notify(Notification{Command: NoticeGroupReload, Gw: r.Gw})
		}()
	}
	return true
}

Cognitive complexity: 15, Cyclomatic complexity: 7

Uses: rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login, rpc.NewSyncForcer, strings.Contains, time.Second, time.Sleep.

func (*RPCStorageHandler) Connect

Connect will establish a connection to the RPC

func (r *RPCStorageHandler) Connect() bool {
	slaveOptions := r.Gw.GetConfig().SlaveOptions

	rpcConfig := rpc.Config{
		UseSSL:			slaveOptions.UseSSL,
		SSLInsecureSkipVerify:	slaveOptions.SSLInsecureSkipVerify,
		SSLMinVersion:		r.Gw.GetConfig().HttpServerOptions.MinVersion,
		SSLMaxVersion:		r.Gw.GetConfig().HttpServerOptions.MaxVersion,
		ConnectionString:	slaveOptions.ConnectionString,
		RPCKey:			slaveOptions.RPCKey,
		APIKey:			slaveOptions.APIKey,
		GroupID:		slaveOptions.GroupID,
		CallTimeout:		slaveOptions.CallTimeout,
		PingTimeout:		slaveOptions.PingTimeout,
		RPCPoolSize:		slaveOptions.RPCPoolSize,
	}

	return rpc.Connect(
		rpcConfig,
		r.SuppressRegister,
		dispatcherFuncs,
		r.getGroupLoginCallback(r.Gw.GetConfig().SlaveOptions.SynchroniserEnabled),
		func() {
			r.Gw.reloadURLStructure(nil)
		},
		r.DoReload,
	)
}

Cognitive complexity: 2, Cyclomatic complexity: 1

Uses: rpc.Config, rpc.Connect.

func (*RPCStorageHandler) Decrement

Decrement will decrement a key in redis

func (r *RPCStorageHandler) Decrement(keyName string) {
	log.Warning("Decrement called")
	_, err := rpc.FuncClientSingleton("Decrement", keyName)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"Decrement",
			err,
			map[string]string{
				"keyName": keyName,
			},
		)
	}
	if r.IsRetriableError(err) {
		if rpc.Login() {
			r.Decrement(keyName)
			return
		}
	}
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) DeleteAllKeys

func (r *RPCStorageHandler) DeleteAllKeys() bool {
	log.Warning("Not implementated")
	return false
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) DeleteKey

DeleteKey will remove a key from the database

func (r *RPCStorageHandler) DeleteKey(keyName string) bool {

	log.Debug("DEL Key was: ", r.Gw.obfuscateKey(keyName))
	log.Debug("DEL Key became: ", r.Gw.obfuscateKey(r.fixKey(keyName)))
	ok, err := rpc.FuncClientSingleton("DeleteKey", r.fixKey(keyName))
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"DeleteKey",
			err,
			map[string]string{
				"keyName":	keyName,
				"fixedKeyName":	r.fixKey(keyName),
			},
		)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.DeleteKey(keyName)
			}
		}
	}

	return ok == true
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) DeleteKeys

DeleteKeys will remove a group of keys in bulk

func (r *RPCStorageHandler) DeleteKeys(keys []string) bool {
	if len(keys) > 0 {
		asInterface := make([]string, len(keys))
		for i, v := range keys {
			asInterface[i] = r.fixKey(v)
		}

		log.Debug("Deleting: ", asInterface)
		ok, err := rpc.FuncClientSingleton("DeleteKeys", asInterface)
		if err != nil {
			rpc.EmitErrorEventKv(
				rpc.FuncClientSingletonCall,
				"DeleteKeys",
				err,
				map[string]string{
					"keys":		strings.Join(keys, ","),
					"asInterface":	strings.Join(asInterface, ","),
				},
			)

			if r.IsRetriableError(err) {
				if rpc.Login() {
					return r.DeleteKeys(keys)
				}
			}
		}

		return ok == true
	}
	log.Debug("RPCStorageHandler called DEL - Nothing to delete")
	return true
}

Cognitive complexity: 12, Cyclomatic complexity: 6

Uses: rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login, strings.Join.

func (*RPCStorageHandler) DeleteRawKey

DeleteKey will remove a key from the database without prefixing, assumes user knows what they are doing

func (r *RPCStorageHandler) DeleteRawKey(keyName string) bool {
	ok, err := rpc.FuncClientSingleton("DeleteRawKey", keyName)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"DeleteRawKey",
			err,
			map[string]string{
				"keyName": keyName,
			},
		)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.DeleteRawKey(keyName)
			}
		}
	}

	return ok == true
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) DeleteRawKeys

func (r *RPCStorageHandler) DeleteRawKeys(keys []string) bool {
	ret, err := rpc.FuncClientSingleton("DeleteRawKeys", keys)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"DeleteKey",
			err,
			nil,
		)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.DeleteRawKeys(keys)
			}
		}
	}
	success, ok := ret.(bool)
	return success && ok
}

Cognitive complexity: 6, Cyclomatic complexity: 5

Uses: rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) DeleteScanMatch

func (r *RPCStorageHandler) DeleteScanMatch(pattern string) bool {
	log.Error("RPCStorageHandler.DeleteScanMatch - Not implemented")
	return false
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) Disconnect

func (r *RPCStorageHandler) Disconnect() error {
	request := model.GroupLoginRequest{
		UserKey:	r.Gw.GetConfig().SlaveOptions.APIKey,
		GroupID:	r.Gw.GetConfig().SlaveOptions.GroupID,
		Node:		r.buildNodeInfo(),
	}

	_, err := rpc.FuncClientSingleton("Disconnect", request)
	return err
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: model.GroupLoginRequest, rpc.FuncClientSingleton.

func (*RPCStorageHandler) Exists

func (r *RPCStorageHandler) Exists(keyName string) (bool, error) {
	log.Error("Not implemented")
	return false, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) GetAndDeleteSet

func (r *RPCStorageHandler) GetAndDeleteSet(keyName string) []interface{} {
	log.Error("RPCStorageHandler.GetAndDeleteSet - Not implemented, please disable your purger")
	return nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*RPCStorageHandler) GetApiDefinitions

GetAPIDefinitions will pull API definitions from the RPC server

func (r *RPCStorageHandler) GetApiDefinitions(orgId string, tags []string) string {
	dr := model.DefRequest{
		OrgId:		orgId,
		Tags:		tags,
		LoadOAS:	true,
	}

	defString, err := rpc.FuncClientSingleton("GetApiDefinitions", dr)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"GetApiDefinitions",
			err,
			map[string]string{
				"orgId":	orgId,
				"tags":		strings.Join(tags, ","),
			},
		)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.GetApiDefinitions(orgId, tags)
			}
		}

		return ""
	}
	log.Debug("API Definitions retrieved")

	if defString == nil {
		log.Warning("RPC Handler: GetApiDefinitions() returned nil, returning empty string")
		return ""
	}
	return defString.(string)
}

Cognitive complexity: 10, Cyclomatic complexity: 5

Uses: model.DefRequest, rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login, strings.Join.

func (*RPCStorageHandler) GetExp

func (r *RPCStorageHandler) GetExp(keyName string) (int64, error) {
	log.Debug("GetExp called")
	value, err := rpc.FuncClientSingleton("GetExp", r.fixKey(keyName))
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"GetExp",
			err,
			map[string]string{
				"keyName":	keyName,
				"fixedKeyName":	r.fixKey(keyName),
			},
		)
		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.GetExp(keyName)
			}
		}
		log.Error("Error trying to get TTL: ", err)
		return 0, storage.ErrKeyNotFound
	}
	return value.(int64), nil
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login, storage.ErrKeyNotFound.

func (*RPCStorageHandler) GetKey

GetKey will retrieve a key from the database

func (r *RPCStorageHandler) GetKey(keyName string) (string, error) {
	start := time.Now()	// get current time
	//	log.Debug("[STORE] Getting WAS: ", keyName)
	//  log.Debug("[STORE] Getting: ", r.fixKey(keyName))
	value, err := r.GetRawKey(r.fixKey(keyName))

	elapsed := time.Since(start)
	log.Debug("GetKey took ", elapsed)

	return value, err
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: time.Now, time.Since.

func (*RPCStorageHandler) GetKeyPrefix

func (r *RPCStorageHandler) GetKeyPrefix() string {
	log.Error("RPCStorageHandler.GetKeyPrefix - Not implemented")
	return ""
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) GetKeys

GetKeys will return all keys according to the filter (filter is a prefix - e.g. tyk.keys.*)

func (r *RPCStorageHandler) GetKeys(filter string) []string {
	log.Error("RPCStorageHandler.GetKeys - Not Implemented")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) GetKeysAndValues

GetKeysAndValues will return all keys and their values - not to be used lightly

func (r *RPCStorageHandler) GetKeysAndValues() map[string]string {

	searchStr := r.KeyPrefix + "*"

	kvPair, err := rpc.FuncClientSingleton("GetKeysAndValues", searchStr)
	if err != nil {
		rpc.EmitErrorEvent(rpc.FuncClientSingletonCall, "GetKeysAndValues", err)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.GetKeysAndValues()
			}
		}

		return nil
	}

	returnValues := make(map[string]string)
	for i, v := range kvPair.(*model.KeysValuesPair).Keys {
		returnValues[r.cleanKey(v)] = kvPair.(*model.KeysValuesPair).Values[i]
	}

	return returnValues

}

Cognitive complexity: 9, Cyclomatic complexity: 5

Uses: model.KeysValuesPair, rpc.EmitErrorEvent, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) GetKeysAndValuesWithFilter

GetKeysAndValuesWithFilter will return all keys and their values with a filter

func (r *RPCStorageHandler) GetKeysAndValuesWithFilter(filter string) map[string]string {

	searchStr := r.KeyPrefix + r.hashKey(filter) + "*"
	log.Debug("[STORE] Getting list by: ", searchStr)

	kvPair, err := rpc.FuncClientSingleton("GetKeysAndValuesWithFilter", searchStr)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"GetKeysAndValuesWithFilter",
			err,
			map[string]string{
				"searchStr": searchStr,
			},
		)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.GetKeysAndValuesWithFilter(filter)
			}
		}

		return nil
	}

	returnValues := make(map[string]string)

	for i, v := range kvPair.(*model.KeysValuesPair).Keys {
		returnValues[r.cleanKey(v)] = kvPair.(*model.KeysValuesPair).Values[i]
	}

	return returnValues
}

Cognitive complexity: 10, Cyclomatic complexity: 5

Uses: model.KeysValuesPair, rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) GetListRange

func (r *RPCStorageHandler) GetListRange(keyName string, from, to int64) ([]string, error) {
	log.Error("Not implemented")
	return nil, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) GetMultiKey

func (r *RPCStorageHandler) GetMultiKey(keyNames []string) ([]string, error) {
	var err error
	var value string

	for _, key := range keyNames {
		value, err = r.GetKey(key)
		if err == nil {
			return []string{value}, nil
		}
	}

	return nil, err
}

Cognitive complexity: 6, Cyclomatic complexity: 3

func (*RPCStorageHandler) GetPolicies

GetPolicies will pull Policies from the RPC server

func (r *RPCStorageHandler) GetPolicies(orgId string) string {
	defString, err := rpc.FuncClientSingleton("GetPolicies", orgId)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"GetPolicies",
			err,
			map[string]string{
				"orgId": orgId,
			},
		)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.GetPolicies(orgId)
			}
		}

		return ""
	}

	if defString != nil {
		return defString.(string)
	}
	return ""
}

Cognitive complexity: 9, Cyclomatic complexity: 5

Uses: rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) GetRawKey

func (r *RPCStorageHandler) GetRawKey(keyName string) (string, error) {
	cacheEnabled := r.Gw.GetConfig().SlaveOptions.EnableRPCCache

	var cacheStore cache.Repository
	if cacheEnabled {
		cacheStore = r.Gw.RPCGlobalCache
		if strings.Contains(keyName, "cert-") {
			cacheStore = r.Gw.RPCCertCache
		}

		if cachedVal, found := cacheStore.Get(keyName); found {
			switch typedVal := cachedVal.(type) {
			case string:
				return typedVal, nil
			case error:
				return "", typedVal
			}
		}
	}

	if rpc.IsEmergencyMode() {
		return "", storage.ErrMDCBConnectionLost
	}

	value, err := rpc.FuncClientSingleton("GetKey", keyName)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"GetKey",
			err,
			map[string]string{"keyName": keyName},
		)
		if r.IsRetriableError(err) && rpc.Login() {
			return r.GetRawKey(keyName)
		}
		if cacheEnabled {
			// Errors, and key not found, should be cached for a small amount of time
			cacheStore.Set(keyName, storage.ErrKeyNotFound, 1)
		}
		return "", storage.ErrKeyNotFound
	}

	if cacheEnabled {
		cacheStore.Set(keyName, value, cache.DefaultExpiration)
	}

	return value.(string), nil
}

Cognitive complexity: 21, Cyclomatic complexity: 13

Uses: cache.DefaultExpiration, cache.Repository, rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.IsEmergencyMode, rpc.Login, storage.ErrKeyNotFound, storage.ErrMDCBConnectionLost, strings.Contains.

func (*RPCStorageHandler) GetRollingWindow

func (r *RPCStorageHandler) GetRollingWindow(keyName string, per int64, pipeline bool) (int, []interface{}) {
	log.Warning("Not Implemented!")
	return 0, nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*RPCStorageHandler) GetSortedSetRange

func (r *RPCStorageHandler) GetSortedSetRange(keyName, scoreFrom, scoreTo string) ([]string, []float64, error) {
	return r.Gw.handleGetSortedSetRange(keyName, scoreFrom, scoreTo)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) IncrememntWithExpire

IncrementWithExpire will increment a key in redis

func (r *RPCStorageHandler) IncrememntWithExpire(keyName string, expire int64) int64 {

	ibd := model.InboundData{
		KeyName:	keyName,
		Expire:		expire,
	}

	val, err := rpc.FuncClientSingleton("IncrememntWithExpire", ibd)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"IncrememntWithExpire",
			err,
			map[string]string{
				"keyName": keyName,
			},
		)
	}
	if r.IsRetriableError(err) {
		if rpc.Login() {
			return r.IncrememntWithExpire(keyName, expire)
		}
	}

	if val == nil {
		log.Warning("RPC increment returned nil value, returning 0")
		return 0
	}

	return val.(int64)

}

Cognitive complexity: 10, Cyclomatic complexity: 5

Uses: model.InboundData, rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login.

func (*RPCStorageHandler) ProcessKeySpaceChanges

ProcessKeySpaceChanges receives an array of keys to be processed, those keys are considered changes in the keyspace in the management layer, they could be: regular keys (hashed, unhashed), revoke oauth client, revoke single oauth token, certificates (added, removed), oauth client (added, updated, removed), user key events (reset)

func (r *RPCStorageHandler) ProcessKeySpaceChanges(keys []string, orgId string) {
	keysToReset := map[string]bool{}
	TokensToBeRevoked := map[string]string{}
	ClientsToBeRevoked := map[string]string{}
	notRegularKeys := map[string]bool{}
	CertificatesToRemove := map[string]string{}
	CertificatesToAdd := map[string]string{}
	OauthClients := map[string]string{}
	apiIDsToDeleteCache := make([]string, 0)
	userKeyResets := make(map[string]string)

	for _, key := range keys {
		splitKeys := strings.Split(key, ":")
		if len(splitKeys) > 1 {
			action := splitKeys[len(splitKeys)-1]
			switch action {
			case ResetQuota:
				keysToReset[splitKeys[0]] = true
			case CertificateRemoved:
				CertificatesToRemove[key] = splitKeys[0]
				notRegularKeys[key] = true
			case CertificateAdded:
				CertificatesToAdd[key] = splitKeys[0]
				notRegularKeys[key] = true
			case OAuthRevokeToken, OAuthRevokeAccessToken, OAuthRevokeRefreshToken:
				TokensToBeRevoked[splitKeys[0]] = key
				notRegularKeys[key] = true
			case OAuthRevokeAllTokens:
				ClientsToBeRevoked[splitKeys[1]] = key
				notRegularKeys[key] = true
			case OauthClientAdded, OauthClientUpdated, OauthClientRemoved:
				OauthClients[splitKeys[0]] = action
				notRegularKeys[key] = true
			case NoticeDeleteAPICache.String():
				apiIDsToDeleteCache = append(apiIDsToDeleteCache, splitKeys[0])
				notRegularKeys[key] = true
			case NoticeUserKeyReset.String():
				keyParts := strings.Split(splitKeys[0], ".")
				if len(keyParts) != 2 {
					log.Error("Invalid user key reset format")
					continue
				}
				userKeyResets[keyParts[0]] = keyParts[1]
			default:
				log.Debug("ignoring processing of action:", action)
			}
		}
	}
	for oldKey, newKey := range userKeyResets {
		if r.Gw.GetConfig().SlaveOptions.APIKey == oldKey {
			config := r.Gw.GetConfig()

			// Updating the key in the KV store if we are using one
			r.Gw.updateKeyInStore(config.Private.EdgeOriginalAPIKeyPath, newKey)

			config.SlaveOptions.APIKey = newKey
			r.Gw.SetConfig(config)
			connected := r.Connect()
			if !connected {
				log.Error("Failed to reconnect to RPC storage")
				continue
			}
		}
		ok := r.Gw.MainNotifier.Notify(Notification{
			Command:	NoticeUserKeyReset,
			Payload:	fmt.Sprintf("%s.%s:%s", oldKey, newKey, NoticeUserKeyReset),
			Gw:		r.Gw,
		})
		if !ok {
			log.Error("Failed to notify other gateways about user key reset")
		}
	}
	// Process OAuth clients
	r.Gw.ProcessOauthClientsOps(OauthClients)

	for clientId, key := range ClientsToBeRevoked {
		splitKeys := strings.Split(key, ":")
		apiId := splitKeys[0]
		clientSecret := splitKeys[2]
		storage, _, err := r.Gw.GetStorageForApi(apiId)
		if err != nil {
			continue
		}
		_, tokens, _ := RevokeAllTokens(storage, clientId, clientSecret)
		keys = append(keys, tokens...)
	}

	//single and specific tokens
	for token, key := range TokensToBeRevoked {
		//key formed as: token:apiId:tokenActionTypeHint
		//but hashed as: token#hashed:apiId:tokenActionTypeHint
		splitKeys := strings.Split(key, ":")
		apiId := splitKeys[1]
		tokenActionTypeHint := splitKeys[2]
		hashedKey := strings.Contains(token, "#hashed")
		if !hashedKey {
			storage, _, err := r.Gw.GetStorageForApi(apiId)
			if err != nil {
				continue
			}
			var tokenTypeHint string
			switch tokenActionTypeHint {
			case OAuthRevokeAccessToken:
				tokenTypeHint = "access_token"
			case OAuthRevokeRefreshToken:
				tokenTypeHint = "refresh_token"
			}
			RevokeToken(storage, token, tokenTypeHint)
		} else {
			token = strings.Split(token, "#")[0]
			r.Gw.handleDeleteHashedKey(token, orgId, apiId, false)
		}
		r.Gw.SessionCache.Delete(token)
		r.Gw.RPCGlobalCache.Delete(r.KeyPrefix + token)
	}

	// remove certs
	for _, certId := range CertificatesToRemove {
		log.Debugf("Removing certificate: %v", certId)
		r.Gw.CertificateManager.Delete(certId, orgId)
		r.Gw.RPCCertCache.Delete("cert-raw-" + certId)
	}

	for _, certId := range CertificatesToAdd {
		log.Debugf("Adding certificate: %v", certId)
		//If we are in a slave node, MDCB Storage GetRaw should get the certificate from MDCB and cache it locally
		content, err := r.Gw.CertificateManager.GetRaw(certId)
		if content == "" && err != nil {
			log.Debugf("Error getting certificate content")
		}
	}

	synchronizerEnabled := r.Gw.GetConfig().SlaveOptions.SynchroniserEnabled
	for _, key := range keys {
		// Skip keys that are user keys to be reset
		splitKeys := strings.Split(key, ":")
		if len(splitKeys) > 1 {
			userKeys := strings.Split(splitKeys[0], ".")
			if len(userKeys) == 2 {
				_, ok := userKeyResets[userKeys[0]]
				if ok {
					continue
				}
			}
		}
		_, isOauthTokenKey := notRegularKeys[key]
		if !isOauthTokenKey {
			splitKeys := strings.Split(key, ":")
			_, resetQuota := keysToReset[splitKeys[0]]

			isHashed := len(splitKeys) > 1 && splitKeys[1] == "hashed"
			var status int
			var err error
			if isHashed {
				log.Info("--> removing cached (hashed) key: ", splitKeys[0])
				key = splitKeys[0]
				_, status = r.Gw.handleDeleteHashedKey(key, orgId, "", resetQuota)
			} else {
				log.Info("--> removing cached key: ", r.Gw.obfuscateKey(key))
				// in case it's a username (basic auth) or custom-key then generate the token
				if storage.TokenOrg(key) == "" {
					key = r.Gw.generateToken(orgId, key)
				}
				_, status = r.Gw.handleDeleteKey(key, orgId, "-1", resetQuota)
				// check if we must remove the key by custom key id
				status, err = r.deleteUsingTokenID(key, orgId, resetQuota, status)
				if err != nil {
					log.Debugf("cannot remove key:%v status: %v", key, status)
				}
			}

			// if key not found locally and synchroniser disabled then we should not pull it from management layer
			if status == http.StatusNotFound && !synchronizerEnabled {
				continue
			}
			r.Gw.getSessionAndCreate(key, r, isHashed, orgId)
			r.Gw.SessionCache.Delete(key)
			r.Gw.RPCGlobalCache.Delete(r.KeyPrefix + key)
		}
	}

	for _, apiID := range apiIDsToDeleteCache {
		if r.Gw.invalidateAPICache(apiID) {
			log.WithField("apiID", apiID).Info("cache invalidated")
			continue
		}

		log.WithField("apiID", apiID).Error("cache invalidation failed")
	}

	// Notify rest of gateways in cluster to flush cache
	n := Notification{
		Command:	KeySpaceUpdateNotification,
		Payload:	strings.Join(keys, ","),
		Gw:		r.Gw,
	}
	r.Gw.MainNotifier.Notify(n)
}

Cognitive complexity: 87, Cyclomatic complexity: 42

Uses: fmt.Sprintf, http.StatusNotFound, storage.TokenOrg, strings.Contains, strings.Join, strings.Split.

func (*RPCStorageHandler) Publish

func (r *RPCStorageHandler) Publish(channel, message string) error {
	log.Warning("RPCStorageHandler.Publish - NO PUBSUB DEFINED")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) RemoveFromList

func (r *RPCStorageHandler) RemoveFromList(keyName, value string) error {
	log.Error("Not implemented")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) RemoveSortedSetRange

func (r *RPCStorageHandler) RemoveSortedSetRange(keyName, scoreFrom, scoreTo string) error {
	return r.Gw.handleRemoveSortedSetRange(keyName, scoreFrom, scoreTo)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) SetExp

func (r *RPCStorageHandler) SetExp(keyName string, timeout int64) error {
	log.Error("RPCStorageHandler.SetExp - Not Implemented")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) SetKey

SetKey will create (or update) a key value in the store

func (r *RPCStorageHandler) SetKey(keyName, session string, timeout int64) error {
	start := time.Now()	// get current time
	ibd := model.InboundData{
		KeyName:	r.fixKey(keyName),
		SessionState:	session,
		Timeout:	timeout,
	}

	_, err := rpc.FuncClientSingleton("SetKey", ibd)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"SetKey",
			err,
			map[string]string{
				"keyName":	keyName,
				"fixedKeyName":	ibd.KeyName,
			},
		)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.SetKey(keyName, session, timeout)
			}
		}

		log.Debug("Error trying to set value:", err)
		return err
	}

	elapsed := time.Since(start)
	log.Debug("SetKey took ", elapsed)
	return nil

}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: model.InboundData, rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login, time.Now, time.Since.

func (*RPCStorageHandler) SetRawKey

func (r *RPCStorageHandler) SetRawKey(keyName, session string, timeout int64) error {
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) SetRollingWindow

SetScrollingWindow is used in the rate limiter to handle rate limits fairly.

func (r *RPCStorageHandler) SetRollingWindow(keyName string, per int64, val string, pipeline bool) (int, []interface{}) {
	start := time.Now()	// get current time
	ibd := model.InboundData{
		KeyName:	keyName,
		Per:		per,
		Expire:		-1,
	}

	intVal, err := rpc.FuncClientSingleton("SetRollingWindow", ibd)
	if err != nil {
		rpc.EmitErrorEventKv(
			rpc.FuncClientSingletonCall,
			"SetRollingWindow",
			err,
			map[string]string{
				"keyName":	keyName,
				"per":		strconv.Itoa(int(per)),
			},
		)

		if r.IsRetriableError(err) {
			if rpc.Login() {
				return r.SetRollingWindow(keyName, per, val, false)
			}
		}
	}

	elapsed := time.Since(start)
	log.Debug("SetRollingWindow took ", elapsed)

	if intVal == nil {
		log.Warning("RPC Handler: SetRollingWindow() returned nil, returning 0")
		return 0, nil
	}

	return intVal.(int), nil

}

Cognitive complexity: 11, Cyclomatic complexity: 5

Uses: model.InboundData, rpc.EmitErrorEventKv, rpc.FuncClientSingleton, rpc.FuncClientSingletonCall, rpc.Login, strconv.Itoa, time.Now, time.Since.

func (*RPCStorageHandler) StartPubSubHandler

StartPubSubHandler will listen for a signal and run the callback with the message

func (r *RPCStorageHandler) StartPubSubHandler(_ string, _ func(*temporalmodel.Message)) error {
	log.Warning("RPCStorageHandler.StartPubSubHandler - NO PUBSUB DEFINED")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RPCStorageHandler) StartRPCKeepaliveWatcher

func (r *RPCStorageHandler) StartRPCKeepaliveWatcher() {
	log.WithFields(logrus.Fields{
		"prefix": "RPC Conn Mgr",
	}).Info("[RPC Conn Mgr] Starting keepalive watcher...")
	for {

		select {
		case <-r.Gw.ctx.Done():
			return
		default:
		}

		if err := r.SetKey("0000", "0000", 10); err != nil {
			log.WithError(err).WithFields(logrus.Fields{
				"prefix": "RPC Conn Mgr",
			}).Warning("Can't connect to RPC layer")

			if r.IsRetriableError(err) {
				if rpc.Login() {
					continue
				}
			}

			if strings.Contains(err.Error(), "Cannot obtain response during timeout") {
				continue
			}
		}

		time.Sleep(10 * time.Second)
	}
}

Cognitive complexity: 14, Cyclomatic complexity: 7

Uses: logrus.Fields, rpc.Login, strings.Contains, time.Second, time.Sleep.

func (*RPCStorageHandler) StartRPCLoopCheck

func (r *RPCStorageHandler) StartRPCLoopCheck(orgId string) {
	if r.Gw.GetConfig().SlaveOptions.DisableKeySpaceSync {
		return
	}

	log.Info("[RPC] Starting keyspace poller")

	for {
		seconds := r.Gw.GetConfig().SlaveOptions.KeySpaceSyncInterval
		r.CheckForKeyspaceChanges(orgId)
		time.Sleep(time.Duration(seconds) * time.Second)
	}
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: time.Duration, time.Second, time.Sleep.

func (*RateCheckMW) Name

func (m *RateCheckMW) Name() string {
	return "RateCheckMW"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RateCheckMW) ProcessRequest

func (m *RateCheckMW) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	// Let's track r/ps
	GlobalRate.Incr(1)
	return nil, http.StatusOK
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: http.StatusOK.

func (*RateLimitAndQuotaCheck) EnabledForSpec

func (k *RateLimitAndQuotaCheck) EnabledForSpec() bool {
	return !k.Spec.DisableRateLimit || !k.Spec.DisableQuota
}

Cognitive complexity: 0, Cyclomatic complexity: 2

func (*RateLimitAndQuotaCheck) Name

func (k *RateLimitAndQuotaCheck) Name() string {
	return "RateLimitAndQuotaCheck"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RateLimitAndQuotaCheck) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (k *RateLimitAndQuotaCheck) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
		return nil, http.StatusOK
	}

	// Skip rate limiting and quotas for looping
	if !ctxCheckLimits(r) {
		return nil, http.StatusOK
	}

	session := ctxGetSession(r)
	rateLimitKey := ctxGetAuthToken(r)
	quotaKey := ""

	if pattern, found := session.MetaData["rate_limit_pattern"]; found {
		if patternString, ok := pattern.(string); ok && patternString != "" {
			if customKeyValue := k.Gw.ReplaceTykVariables(r, patternString, false); customKeyValue != "" {
				rateLimitKey = customKeyValue
				quotaKey = customKeyValue
			}
		}
	}

	storeRef := k.Gw.GlobalSessionManager.Store()
	reason := k.Gw.SessionLimiter.ForwardMessage(
		r,
		session,
		rateLimitKey,
		quotaKey,
		storeRef,
		!k.Spec.DisableRateLimit,
		!k.Spec.DisableQuota,
		k.Spec,
		false,
	)

	throttleRetryLimit := session.ThrottleRetryLimit
	throttleInterval := session.ThrottleInterval

	if len(session.AccessRights) > 0 {
		if rights, ok := session.AccessRights[k.Spec.APIID]; ok {
			if !rights.Limit.IsEmpty() {
				throttleInterval = rights.Limit.ThrottleInterval
				throttleRetryLimit = rights.Limit.ThrottleRetryLimit
			}
		}
	}

	k.emitRateLimitEvents(r, rateLimitKey)

	switch reason {
	case sessionFailNone:
	case sessionFailRateLimit:
		err, errCode := k.handleRateLimitFailure(r, event.RateLimitExceeded, "Rate Limit Exceeded", rateLimitKey)
		if throttleRetryLimit > 0 {
			for {
				ctxIncThrottleLevel(r, throttleRetryLimit)
				time.Sleep(time.Duration(throttleInterval * float64(time.Second)))

				reason = k.Gw.SessionLimiter.ForwardMessage(
					r,
					session,
					rateLimitKey,
					quotaKey,
					storeRef,
					!k.Spec.DisableRateLimit,
					!k.Spec.DisableQuota,
					k.Spec,
					true,
				)

				log.WithFields(logrus.Fields{
					"middleware":	"RateLimitAndQuotaCheck",
					"func":		"ProcessRequest",
				}).Debugf("after dry-run (reason: '%s')", reason)

				if ctxThrottleLevel(r) > throttleRetryLimit {
					break
				}

				if reason == sessionFailNone {
					return k.ProcessRequest(w, r, nil)
				}
			}
		}
		return err, errCode

	case sessionFailQuota:
		return k.handleQuotaFailure(r, rateLimitKey)
	case sessionFailInternalServerError:
		return ProxyingRequestFailedErr, http.StatusInternalServerError
	default:
		// Other reason? Still not allowed
		return errors.New("Access denied"), http.StatusForbidden
	}
	// Run the trigger monitor
	if k.Spec.GlobalConfig.Monitor.MonitorUserKeys {
		k.Gw.SessionMonitor.Check(session, rateLimitKey)
	}

	// Request is valid, carry on
	return nil, http.StatusOK
}

Cognitive complexity: 34, Cyclomatic complexity: 20

Uses: errors.New, event.RateLimitExceeded, http.StatusForbidden, http.StatusInternalServerError, http.StatusOK, logrus.Fields, time.Duration, time.Second, time.Sleep.

func (*RateLimitForAPI) EnabledForSpec

func (k *RateLimitForAPI) EnabledForSpec() bool {
	if !k.shouldEnable() {
		return false
	}

	// We'll init here
	k.keyName = "apilimiter-" + k.Spec.OrgID + k.Spec.APIID

	// Set last updated on each load to ensure we always use a new rate limit bucket
	k.apiSess = &user.SessionState{
		Rate:		k.Spec.GlobalRateLimit.Rate,
		Per:		k.Spec.GlobalRateLimit.Per,
		LastUpdated:	strconv.Itoa(int(time.Now().UnixNano())),
	}
	k.apiSess.SetKeyHash(storage.HashKey(k.keyName, k.Gw.GetConfig().HashKeys))

	return true
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: storage.HashKey, strconv.Itoa, time.Now, user.SessionState.

func (*RateLimitForAPI) Name

func (k *RateLimitForAPI) Name() string {
	return "RateLimitForAPI"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RateLimitForAPI) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (k *RateLimitForAPI) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	// Skip rate limiting and quotas for looping
	if !ctxCheckLimits(r) {
		return nil, http.StatusOK
	}

	storeRef := k.Gw.GlobalSessionManager.Store()
	customQuotaKey := ""

	reason := k.Gw.SessionLimiter.ForwardMessage(
		r,
		k.getSession(r),
		k.keyName,
		customQuotaKey,
		storeRef,
		true,
		false,
		k.Spec,
		false,
	)

	k.emitRateLimitEvents(r, k.keyName)

	if reason == sessionFailRateLimit {
		return k.handleRateLimitFailure(r, event.RateLimitExceeded, "API Rate Limit Exceeded", k.keyName)
	}

	// Request is valid, carry on
	return nil, http.StatusOK
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: event.RateLimitExceeded, http.StatusOK.

func (*RedisAnalyticsHandler) Flush

Flush will stop the analytics processing and empty the analytics buffer and then re-init the workers again

func (r *RedisAnalyticsHandler) Flush() {
	r.Stop()

	r.Start()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RedisAnalyticsHandler) Init

func (r *RedisAnalyticsHandler) Init() {
	r.globalConf = r.Gw.GetConfig()
	if r.globalConf.AnalyticsConfig.EnableGeoIP {
		if db, err := maxminddb.Open(r.globalConf.AnalyticsConfig.GeoIPDBLocation); err != nil {
			log.Error("Failed to init GeoIP Database: ", err)
		} else {
			r.GeoIPDB = db
		}
	}

	r.Store.Connect()
	ps := r.Gw.GetConfig().AnalyticsConfig.PoolSize
	recordsBufferSize := r.globalConf.AnalyticsConfig.RecordsBufferSize

	r.workerBufferSize = recordsBufferSize / uint64(ps)
	log.WithField("workerBufferSize", r.workerBufferSize).Debug("Analytics pool worker buffer size")
	r.enableMultipleAnalyticsKeys = r.globalConf.AnalyticsConfig.EnableMultipleAnalyticsKeys
	r.analyticsSerializer = serializer.NewAnalyticsSerializer(r.globalConf.AnalyticsConfig.SerializerType)

	r.Start()
}

Cognitive complexity: 6, Cyclomatic complexity: 3

Uses: maxminddb.Open, serializer.NewAnalyticsSerializer.

func (*RedisAnalyticsHandler) RecordHit

RecordHit will store an analytics.Record in Redis

func (r *RedisAnalyticsHandler) RecordHit(record *analytics.AnalyticsRecord) error {
	if r.mockEnabled {
		r.mockRecordHit(record)
		return nil
	}

	// check if we should stop sending records 1st
	if atomic.LoadUint32(&r.shouldStop) > 0 {
		return nil
	}

	// just send record to channel consumed by pool of workers
	// leave all data crunching and Redis I/O work for pool workers
	r.mu.Lock()
	r.recordsChan <- record
	r.mu.Unlock()

	return nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: atomic.LoadUint32.

func (*RedisAnalyticsHandler) Start

Start initialize the records channel and spawn the record workers

func (r *RedisAnalyticsHandler) Start() {
	r.recordsChan = make(chan *analytics.AnalyticsRecord, r.globalConf.AnalyticsConfig.RecordsBufferSize)
	atomic.SwapUint32(&r.shouldStop, 0)
	for i := 0; i < r.Gw.GetConfig().AnalyticsConfig.PoolSize; i++ {
		r.poolWg.Add(1)
		go r.recordWorker()
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: analytics.AnalyticsRecord, atomic.SwapUint32.

func (*RedisAnalyticsHandler) Stop

Stop stops the analytics processing

func (r *RedisAnalyticsHandler) Stop() {
	// flag to stop sending records into channel
	atomic.SwapUint32(&r.shouldStop, 1)

	// close channel to stop workers
	r.mu.Lock()
	close(r.recordsChan)
	r.mu.Unlock()

	// wait for all workers to be done
	r.poolWg.Wait()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: atomic.SwapUint32.

func (*RedisCacheMiddleware) CreateCheckSum

func (m *RedisCacheMiddleware) CreateCheckSum(req *http.Request, keyName string, regex string, additionalKeyFromHeaders string) (string, error) {
	h := md5.New()

	// Compose key into string
	key := req.Method + "-" + req.URL.String()
	if additionalKeyFromHeaders != "" {
		key = key + "-" + additionalKeyFromHeaders
	}

	_, err := io.WriteString(h, key)
	if err != nil {
		return "", err
	}

	if e := addBodyHash(req, regex, h); e != nil {
		return "", e
	}

	reqChecksum := hex.EncodeToString(h.Sum(nil))
	return m.Spec.APIID + keyName + reqChecksum, nil
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: hex.EncodeToString, io.WriteString, md5.New.

func (*RedisCacheMiddleware) EnabledForSpec

func (m *RedisCacheMiddleware) EnabledForSpec() bool {
	return m.Spec.CacheOptions.EnableCache
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RedisCacheMiddleware) Init

func (m *RedisCacheMiddleware) Init() {
	m.sh = SuccessHandler{m.BaseMiddleware}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*RedisCacheMiddleware) Name

func (m *RedisCacheMiddleware) Name() string {
	return "RedisCacheMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RedisCacheMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (m *RedisCacheMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	t1 := time.Now()

	var stat RequestStatus
	var cacheKeyRegex string
	var cacheMeta *EndPointCacheMeta

	version, _ := m.Spec.Version(r)
	versionPaths := m.Spec.RxPaths[version.Name]

	// Lets see if we can throw a sledgehammer at this
	if m.Spec.CacheOptions.CacheAllSafeRequests && isSafeMethod(r.Method) {
		stat = StatusCached
	}

	if stat != StatusCached {
		// New request checker, more targeted, less likely to fail
		found, meta := m.Spec.CheckSpecMatchesStatus(r, versionPaths, Cached)
		if found {
			cacheMeta = meta.(*EndPointCacheMeta)
			stat = StatusCached
			cacheKeyRegex = cacheMeta.CacheKeyRegex
		}
	}
	// Cached route matched, let go
	if stat != StatusCached {
		m.Logger().Debug("Not a cached path")
		return nil, http.StatusOK
	}
	token := ctxGetAuthToken(r)

	// No authentication data? use the IP.
	if token == "" {
		token = request.RealIP(r)
	}

	var retBlob string
	key, err := m.CreateCheckSum(r, token, cacheKeyRegex, m.getCacheKeyFromHeaders(r))
	if err != nil {
		m.Logger().Debug("Error creating checksum. Skipping cache check")
		return nil, http.StatusOK
	}

	cacheOnlyResponseCodes := m.Spec.CacheOptions.CacheOnlyResponseCodes
	timeout := m.Spec.CacheOptions.CacheTimeout
	if cacheMeta != nil {
		// override api level CacheOnlyResponseCodes by endpoint level if provided
		if len(cacheMeta.CacheOnlyResponseCodes) > 0 {
			cacheOnlyResponseCodes = cacheMeta.CacheOnlyResponseCodes
		}

		// override api level Timout by endpoint level if provided
		if cacheMeta.Timeout > 0 {
			timeout = cacheMeta.Timeout
		}
	}

	ctxSetCacheOptions(r, &cacheOptions{
		key:			key,
		cacheOnlyResponseCodes:	cacheOnlyResponseCodes,
		timeout:		timeout,
	})

	retBlob, err = m.store.GetKey(key)
	if err != nil {
		// Record not found, continue with the middleware chain
		return nil, http.StatusOK
	}

	cachedData, timestamp, err := m.decodePayload(retBlob)
	if err != nil {
		// Tere was an issue with this cache entry - lets remove it:
		m.store.DeleteKey(key)
		return nil, http.StatusOK
	}

	if m.isTimeStampExpired(timestamp) || len(cachedData) == 0 {
		m.store.DeleteKey(key)
		return nil, http.StatusOK
	}

	bufData := bufio.NewReader(strings.NewReader(cachedData))
	newRes, err := http.ReadResponse(bufData, r)
	if err != nil {
		m.Logger().WithError(err).Error("Could not create response object")
		m.store.DeleteKey(key)
		return nil, http.StatusOK
	}

	nopCloseResponseBody(newRes)

	defer newRes.Body.Close()
	for _, h := range hopHeaders {
		newRes.Header.Del(h)
	}

	session := ctxGetSession(r)

	// Only add ratelimit data to keyed sessions
	if session != nil {
		quotaMax, quotaRemaining, _, quotaRenews := session.GetQuotaLimitByAPIID(m.Spec.APIID)
		newRes.Header.Set(header.XRateLimitLimit, strconv.Itoa(int(quotaMax)))
		newRes.Header.Set(header.XRateLimitRemaining, strconv.Itoa(int(quotaRemaining)))
		newRes.Header.Set(header.XRateLimitReset, strconv.Itoa(int(quotaRenews)))
	}
	newRes.Header.Set(cachedResponseHeader, "1")

	copyHeader(w.Header(), newRes.Header, m.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey)

	if reqEtag := r.Header.Get("If-None-Match"); reqEtag != "" {
		if respEtag := newRes.Header.Get("Etag"); respEtag != "" {
			if strings.Contains(reqEtag, respEtag) {
				newRes.StatusCode = http.StatusNotModified
			}
		}
	}

	w.WriteHeader(newRes.StatusCode)
	if newRes.StatusCode != http.StatusNotModified {
		m.Proxy.CopyResponse(w, newRes.Body, 0)
	}

	// Record analytics
	if !m.Spec.DoNotTrack {
		ms := DurationToMillisecond(time.Since(t1))
		m.sh.RecordHit(r, analytics.Latency{Total: int64(ms)}, newRes.StatusCode, newRes, true)
	}

	// Stop any further execution after we wrote cache out
	return nil, mwStatusRespond
}

Cognitive complexity: 44, Cyclomatic complexity: 23

Uses: analytics.Latency, bufio.NewReader, header.XRateLimitLimit, header.XRateLimitRemaining, header.XRateLimitReset, http.ReadResponse, http.StatusNotModified, http.StatusOK, request.RealIP, strconv.Itoa, strings.Contains, strings.NewReader, time.Now, time.Since.

func (*RedisNotifier) Notify

Notify will send a notification to a channel

func (r *RedisNotifier) Notify(notif interface{}) bool {
	if n, ok := notif.(Notification); ok {
		n.Sign()
		notif = n
	}

	toSend, err := json.Marshal(notif)

	if err != nil {

		pubSubLog.Error("Problem marshalling notification: ", err)
		return false
	}

	// pubSubLog.Debug("Sending notification", notif)

	if err := r.store.Publish(r.channel, string(toSend)); err != nil {
		if !errors.Is(err, storage.ErrRedisIsDown) {
			pubSubLog.Error("Could not send notification: ", err)
		}
		return false
	}

	return true
}

Cognitive complexity: 9, Cyclomatic complexity: 5

Uses: errors.Is, json.Marshal, storage.ErrRedisIsDown.

func (*RedisOsinStorageInterface) Clone

func (r *RedisOsinStorageInterface) Clone() osin.Storage {
	return r
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RedisOsinStorageInterface) Close

func (r *RedisOsinStorageInterface) Close()	{}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RedisOsinStorageInterface) DeleteClient

DeleteClient Removes a client from the system

func (r *RedisOsinStorageInterface) DeleteClient(id string, orgID string, ignorePrefix bool) error {
	key := prefixClient + id
	if ignorePrefix {
		key = id
	}

	// Get the raw vals:
	clientJSON, err := r.store.GetKey(key)
	keyForSet := prefixClientset + prefixClient	// Org ID
	if err == nil {
		log.Debug("Removing from set")
		r.store.RemoveFromSet(keyForSet, clientJSON)
	}

	r.store.DeleteKey(key)

	indexKey := prefixClientIndexList + orgID
	// delete from oauth client
	r.store.RemoveFromList(indexKey, key)

	// delete list of tokens for this client
	r.store.DeleteKey(prefixClientTokens + id)
	if r.Gw.GetConfig().SlaveOptions.UseRPC {
		r.redisStore.RemoveFromList(indexKey, key)
		r.redisStore.DeleteKey(prefixClientTokens + id)
		r.redisStore.RemoveFromSet(keyForSet, clientJSON)
	}

	return nil
}

Cognitive complexity: 6, Cyclomatic complexity: 4

func (*RedisOsinStorageInterface) GetClient

GetClient will retrieve client data

func (r *RedisOsinStorageInterface) GetClient(id string) (osin.Client, error) {
	key := prefixClient + id

	log.Debug("Getting client ID:", id)
	clientJSON, err := r.store.GetKey(key)
	if err != nil {
		log.Debugf("Failure retrieving client ID key %q: %v", key, err)
		return nil, err
	}

	client := new(OAuthClient)
	if err := json.Unmarshal([]byte(clientJSON), &client); err != nil {
		log.Debug("Couldn't unmarshal OAuth client object: ", err)
	}
	return client, nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: json.Unmarshal.

func (*RedisOsinStorageInterface) GetClientNoPrefix

GetClientNoPrefix will retrieve client data, but not assign a prefix - this is an unfortunate hack, but we don't want to change the signature in Osin for GetClient to support the odd Redis prefixing

func (r *RedisOsinStorageInterface) GetClientNoPrefix(id string) (osin.Client, error) {

	key := id

	clientJSON, err := r.store.GetKey(key)

	if err != nil {
		log.Error("Failure retrieving client ID key: ", err)
		return nil, err
	}

	client := new(OAuthClient)
	if err := json.Unmarshal([]byte(clientJSON), client); err != nil {
		log.Error("Couldn't unmarshal OAuth client object: ", err)
	}

	return client, nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: json.Unmarshal.

func (*RedisOsinStorageInterface) GetClientTokens

func (r *RedisOsinStorageInterface) GetClientTokens(id string) ([]OAuthClientToken, error) {
	key := prefixClientTokens + id

	// use current timestamp as a start score so all expired tokens won't be picked
	nowTs := time.Now().Unix()
	startScore := strconv.FormatInt(nowTs, 10)

	log.Info("Getting client tokens sorted list:", key)

	tokens, scores, err := r.redisStore.GetSortedSetRange(key, startScore, "+inf")
	if err != nil {
		return nil, err
	}

	// clean up expired tokens in sorted set (remove all tokens with score up to current timestamp minus retention)
	if r.Gw.GetConfig().OauthTokenExpiredRetainPeriod > 0 {
		cleanupStartScore := strconv.FormatInt(nowTs-int64(r.Gw.GetConfig().OauthTokenExpiredRetainPeriod), 10)
		go r.redisStore.RemoveSortedSetRange(key, "-inf", cleanupStartScore)
	}

	if len(tokens) == 0 {
		return []OAuthClientToken{}, nil
	}

	// convert sorted set data and scores into reply struct
	tokensData := make([]OAuthClientToken, len(tokens))
	for i := range tokens {
		tokensData[i] = OAuthClientToken{
			Token:		tokens[i],
			Expires:	int64(scores[i]),	// we store expire timestamp as a score
		}
	}

	return tokensData, nil
}

Cognitive complexity: 11, Cyclomatic complexity: 5

Uses: strconv.FormatInt, time.Now.

func (*RedisOsinStorageInterface) GetClients

GetClients will retrieve a list of clients for a prefix

func (r *RedisOsinStorageInterface) GetClients(filter string, orgID string, ignorePrefix bool) ([]ExtendedOsinClientInterface, error) {
	key := prefixClient + filter
	if ignorePrefix {
		key = filter
	}

	indexKey := prefixClientIndexList + orgID

	var clientJSON map[string]string
	if !r.Gw.GetConfig().Storage.EnableCluster {
		exists, _ := r.store.Exists(indexKey)
		if exists {
			keys, err := r.store.GetListRange(indexKey, 0, -1)
			if err != nil {
				log.Error("Couldn't get OAuth client index list: ", err)
				return nil, err
			}
			keyVals, err := r.store.GetMultiKey(keys)
			if err != nil {
				log.Error("Couldn't get OAuth client index list values: ", err)
				return nil, err
			}

			clientJSON = make(map[string]string)
			for i, key := range keys {
				clientJSON[key] = keyVals[i]
			}
		} else {
			clientJSON = r.store.GetKeysAndValuesWithFilter(key)
			for key := range clientJSON {
				r.store.AppendToSet(indexKey, key)
			}
		}
	} else {
		keyForSet := prefixClientset + prefixClient	// Org ID
		var err error
		if clientJSON, err = r.store.GetSet(keyForSet); err != nil {
			return nil, err
		}
	}

	theseClients := []ExtendedOsinClientInterface{}
	for _, clientJSON := range clientJSON {
		client := new(OAuthClient)
		if err := json.Unmarshal([]byte(clientJSON), &client); err != nil {
			log.Error("Couldn't unmarshal OAuth client object: ", err)
			return nil, err
		}
		theseClients = append(theseClients, client)
	}

	return theseClients, nil
}

Cognitive complexity: 28, Cyclomatic complexity: 11

Uses: json.Unmarshal.

func (*RedisOsinStorageInterface) GetExtendedClient

func (r *RedisOsinStorageInterface) GetExtendedClient(id string) (ExtendedOsinClientInterface, error) {
	osinClient, err := r.GetClient(id)
	if err != nil {
		log.WithError(err).Error("Failure retrieving client ID key")
		return nil, err
	}

	return osinClient.(*OAuthClient), err
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*RedisOsinStorageInterface) GetExtendedClientNoPrefix

GetExtendedClientNoPrefix custom getter to handle prefixing issues in Redis,

func (r *RedisOsinStorageInterface) GetExtendedClientNoPrefix(id string) (ExtendedOsinClientInterface, error) {
	osinClient, err := r.GetClientNoPrefix(id)
	if err != nil {
		log.WithError(err).Error("Failure retrieving client ID key")
		return nil, err
	}
	return osinClient.(*OAuthClient), err
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*RedisOsinStorageInterface) GetPaginatedClientTokens

GetPaginatedClientTokens returns all tokens associated with the given id. It returns the tokens, the total number of pages of the tokens after pagination and an error if any

func (r *RedisOsinStorageInterface) GetPaginatedClientTokens(id string, page int) ([]OAuthClientToken, int, error) {
	key := prefixClientTokens + id

	// use current timestamp as a start score so all expired tokens won't be picked
	nowTs := time.Now().Unix()
	startScore := strconv.FormatInt(nowTs, 10)

	log.Info("Getting client tokens sorted list:", key)

	tokens, scores, err := r.store.GetSortedSetRange(key, startScore, "+inf")
	if err != nil {
		return nil, 0, err
	}

	// clean up expired tokens in sorted set (remove all tokens with score up to current timestamp minus retention)
	if r.Gw.GetConfig().OauthTokenExpiredRetainPeriod > 0 {
		cleanupStartScore := strconv.FormatInt(nowTs-int64(r.Gw.GetConfig().OauthTokenExpiredRetainPeriod), 10)
		go r.store.RemoveSortedSetRange(key, "-inf", cleanupStartScore)
	}

	itemsPerPage := 100

	tokenNumber := len(tokens)

	if tokenNumber == 0 {
		return []OAuthClientToken{}, 0, nil
	}

	startIdx := (page - 1) * itemsPerPage
	endIdx := startIdx + itemsPerPage

	if tokenNumber < startIdx {
		startIdx = tokenNumber
	}

	if tokenNumber < endIdx {
		endIdx = tokenNumber
	}

	totalPages := int(math.Ceil(float64(len(tokens)) / float64(itemsPerPage)))

	tokens = tokens[startIdx:endIdx]

	// convert sorted set data and scores into reply struct
	tokensData := make([]OAuthClientToken, len(tokens))
	for i := range tokens {
		tokensData[i] = OAuthClientToken{
			Token:		tokens[i],
			Expires:	int64(scores[i]),	// we store expire timestamp as a score
		}
	}

	return tokensData, totalPages, nil
}

Cognitive complexity: 15, Cyclomatic complexity: 7

Uses: math.Ceil, strconv.FormatInt, time.Now.

func (*RedisOsinStorageInterface) GetUser

LoadRefresh will load access data from Redis

func (r *RedisOsinStorageInterface) GetUser(username string) (*user.SessionState, error) {
	key := username
	log.Debug("Loading User key: ", key)
	accessJSON, err := r.store.GetRawKey(key)

	if err != nil {
		log.Error("Failure retreiving access token by key: ", err)
		return nil, err
	}

	// new interface means having to make this nested... ick.
	session := &user.SessionState{}
	if err := json.Unmarshal([]byte(accessJSON), session); err != nil {
		log.Error("Couldn't unmarshal OAuth auth data object (LoadRefresh): ", err,
			"; Decoding: ", accessJSON)
		return nil, err
	}

	return session, nil
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: json.Unmarshal, user.SessionState.

func (*RedisOsinStorageInterface) LoadAccess

LoadAccess will load access data from redis

func (r *RedisOsinStorageInterface) LoadAccess(token string) (*osin.AccessData, error) {
	key := prefixAccess + storage.HashKey(token, r.Gw.GetConfig().HashKeys)
	log.Debug("Loading ACCESS key: ", key)
	accessJSON, err := r.store.GetKey(key)

	if err != nil {
		// Fallback to unhashed value for backward compatibility
		key = prefixAccess + token
		accessJSON, err = r.store.GetKey(key)

		if err != nil {
			log.Error("Failure retreiving access token by key: ", err)
			return nil, err
		}
	}

	accessData := osin.AccessData{Client: new(OAuthClient)}
	if err := json.Unmarshal([]byte(accessJSON), &accessData); err != nil {
		log.Error("Couldn't unmarshal OAuth auth data object (LoadAccess): ", err)
		return nil, err
	}

	return &accessData, nil
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: json.Unmarshal, osin.AccessData, storage.HashKey.

func (*RedisOsinStorageInterface) LoadAuthorize

LoadAuthorize loads auth data from redis

func (r *RedisOsinStorageInterface) LoadAuthorize(code string) (*osin.AuthorizeData, error) {
	key := prefixAuth + code
	log.Debug("Loading auth code: ", key)
	authJSON, err := r.store.GetKey(key)

	if err != nil {
		log.Error("Failure retreiving auth code key: ", err)
		return nil, err
	}

	authData := osin.AuthorizeData{Client: new(OAuthClient)}
	if err := json.Unmarshal([]byte(authJSON), &authData); err != nil {
		log.Error("Couldn't unmarshal OAuth auth data object (LoadAuthorize): ", err)
		return nil, err
	}

	return &authData, nil
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: json.Unmarshal, osin.AuthorizeData.

func (*RedisOsinStorageInterface) LoadRefresh

LoadRefresh will load access data from Redis

func (r *RedisOsinStorageInterface) LoadRefresh(token string) (*osin.AccessData, error) {
	key := prefixRefresh + token
	log.Debug("Loading REFRESH key: ", key)
	accessJSON, err := r.store.GetKey(key)

	if err != nil {
		log.Error("Failure retreiving access token by key: ", err)
		return nil, err
	}

	// new interface means having to make this nested... ick.
	accessData := osin.AccessData{Client: new(OAuthClient)}
	if err := json.Unmarshal([]byte(accessJSON), &accessData); err != nil {
		log.Error("Couldn't unmarshal OAuth auth data object (LoadRefresh): ", err,
			"; Decoding: ", accessJSON)
		return nil, err
	}

	return &accessData, nil
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: json.Unmarshal, osin.AccessData.

func (*RedisOsinStorageInterface) RemoveAccess

RemoveAccess will remove access data from Redis

func (r *RedisOsinStorageInterface) RemoveAccess(token string) error {

	access, err := r.LoadAccess(token)
	if err == nil {
		key := prefixClientTokens + access.Client.GetId()
		//remove from set oauth.client-tokens
		log.Info("removing token from oauth client tokens list")
		limit := strconv.FormatFloat(float64(access.ExpireAt().Unix()), 'f', 0, 64)
		r.redisStore.RemoveSortedSetRange(key, limit, limit)
	} else {
		log.Warning("Cannot load access token:", token)
	}

	key := prefixAccess + storage.HashKey(token, r.Gw.GetConfig().HashKeys)
	r.store.DeleteKey(key)
	// remove the access token from central storage too
	r.sessionManager.RemoveSession(r.orgID, token, false)
	return nil
}

Cognitive complexity: 4, Cyclomatic complexity: 2

Uses: storage.HashKey, strconv.FormatFloat.

func (*RedisOsinStorageInterface) RemoveAuthorize

RemoveAuthorize removes authorisation keys from redis

func (r *RedisOsinStorageInterface) RemoveAuthorize(code string) error {
	key := prefixAuth + code
	r.store.DeleteKey(key)
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RedisOsinStorageInterface) RemoveRefresh

RemoveRefresh will remove a refresh token from redis

func (r *RedisOsinStorageInterface) RemoveRefresh(token string) error {
	log.Debug("is going to revoke refresh token: ", token)
	key := prefixRefresh + token
	r.store.DeleteKey(key)
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RedisOsinStorageInterface) SaveAccess

SaveAccess will save a token and it's access data to redis

func (r *RedisOsinStorageInterface) SaveAccess(accessData *osin.AccessData) error {
	authDataJSON, err := json.Marshal(accessData)
	if err != nil {
		return err
	}
	key := prefixAccess + storage.HashKey(accessData.AccessToken, r.Gw.GetConfig().HashKeys)
	log.Debug("Saving ACCESS key: ", key)

	// Overide default ExpiresIn:
	if oauthTokenExpire := r.Gw.GetConfig().OauthTokenExpire; oauthTokenExpire != 0 {
		accessData.ExpiresIn = oauthTokenExpire
	}

	err = r.store.SetKey(key, string(authDataJSON), int64(accessData.ExpiresIn))
	if err != nil {
		log.WithError(err).Error("could not save access data")
	}

	// add code to list of tokens for this client
	sortedListKey := prefixClientTokens + accessData.Client.GetId()
	log.Debug("Adding ACCESS key to sorted list: ", sortedListKey)
	r.redisStore.AddToSortedSet(
		sortedListKey,
		storage.HashKey(accessData.AccessToken, r.Gw.GetConfig().HashKeys),
		float64(accessData.CreatedAt.Unix()+int64(accessData.ExpiresIn)),	// set score as token expire timestamp
	)

	// Create a user.SessionState object and register it with the authmanager
	newSession := user.NewSessionState()

	// ------
	checkPolicy := true
	if accessData.UserData != nil {
		checkPolicy = false
		err := json.Unmarshal([]byte(accessData.UserData.(string)), newSession)
		if err != nil {
			log.Info("Couldn't decode user.SessionState from UserData, checking policy: ", err)
			checkPolicy = true
		}
	}

	if checkPolicy {
		// defined in JWT middleware
		sessionFromPolicy, err := r.Gw.generateSessionFromPolicy(accessData.Client.GetPolicyID(), "", false)
		if err != nil {
			return errors.New("Couldn't use policy or key rules to create token, failing")
		}

		newSession = &sessionFromPolicy
	}

	// ------

	// Set the client ID for analytics
	newSession.OauthClientID = accessData.Client.GetId()

	// Override timeouts so that we can be in sync with Osin
	newSession.Expires = time.Now().Unix() + int64(accessData.ExpiresIn)

	c, ok := accessData.Client.(*OAuthClient)
	if ok && c.MetaData != nil {
		if newSession.MetaData == nil {
			newSession.MetaData = make(map[string]interface{})
		}

		// Allow session inherit and *override* client values
		for k, v := range c.MetaData.(map[string]interface{}) {
			if _, found := newSession.MetaData[k]; !found {
				newSession.MetaData[k] = v
			}
		}
	}

	sessionLifetime := r.Gw.ApplyLifetime(newSession)

	// Use the default session expiry here as this is OAuth
	r.sessionManager.UpdateSession(accessData.AccessToken, newSession, sessionLifetime, false)

	// Store the refresh token too
	if accessData.RefreshToken != "" {
		accessDataJSON, err := json.Marshal(accessData)
		if err != nil {
			return err
		}
		key := prefixRefresh + accessData.RefreshToken
		refreshExpire := int64(1209600)	// 14 days
		if oauthRefreshExpire := r.Gw.GetConfig().OauthRefreshExpire; oauthRefreshExpire != 0 {
			refreshExpire = oauthRefreshExpire
		}
		log.Debug("STORING ACCESS DATA: ", string(accessDataJSON))
		err = r.store.SetKey(key, string(accessDataJSON), refreshExpire)
		if err != nil {
			log.WithError(err).Error("could not save access data")
		}
		return err
	}

	return nil
}

Cognitive complexity: 33, Cyclomatic complexity: 17

Uses: errors.New, json.Marshal, json.Unmarshal, storage.HashKey, time.Now, user.NewSessionState.

func (*RedisOsinStorageInterface) SaveAuthorize

SaveAuthorize saves authorisation data to Redis

func (r *RedisOsinStorageInterface) SaveAuthorize(authData *osin.AuthorizeData) error {
	authDataJSON, err := json.Marshal(&authData)
	if err != nil {
		return err
	}
	key := prefixAuth + authData.Code
	log.Debug("Saving auth code: ", key)

	err = r.store.SetKey(key, string(authDataJSON), int64(authData.ExpiresIn))

	return nil
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: json.Marshal.

func (*RedisOsinStorageInterface) SetClient

SetClient creates client data

func (r *RedisOsinStorageInterface) SetClient(id string, orgID string, client osin.Client, ignorePrefix bool) error {
	clientDataJSON, err := json.Marshal(client)

	if err != nil {
		log.Error("Couldn't marshal client data: ", err)
		return err
	}

	key := prefixClient + id

	if ignorePrefix {
		key = id
	}

	log.Debug("CREATING: ", key)

	err = r.store.SetKey(key, string(clientDataJSON), 0)
	if err != nil {
		log.WithError(err).Error("could not save oauth client data")
	}

	keyForSet := prefixClientset + prefixClient	// Org ID

	indexKey := prefixClientIndexList + orgID
	//check if the indexKey exists
	exists, err := r.store.Exists(indexKey)
	if err != nil {
		return err
	}
	// if it exists, delete it to avoid duplicity in the client index list
	if exists {
		r.store.RemoveFromList(indexKey, key)
	}
	// append to oauth client index list
	r.store.AppendToSet(indexKey, key)

	// In set, there is no option for update so the existing client should be removed before adding new one.
	set, _ := r.store.GetSet(keyForSet)
	for _, v := range set {
		if strings.Contains(v, client.GetId()) {
			r.store.RemoveFromSet(keyForSet, v)
		}
	}

	r.store.AddToSet(keyForSet, string(clientDataJSON))
	return nil
}

Cognitive complexity: 15, Cyclomatic complexity: 8

Uses: json.Marshal, strings.Contains.

func (*RedisOsinStorageInterface) SetUser

func (r *RedisOsinStorageInterface) SetUser(username string, session *user.SessionState, timeout int64) error {
	key := username
	authDataJSON, err := json.Marshal(session)
	if err != nil {
		return err
	}

	if err := r.store.SetRawKey(key, string(authDataJSON), timeout); err != nil {
		log.Error("Failure setting user token by key: ", err)
		return err
	}

	return nil

}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: json.Marshal.

func (*RedisPurger) PurgeCache

func (r *RedisPurger) PurgeCache() {
	expireAfter := r.Gw.GetConfig().AnalyticsConfig.StorageExpirationTime
	if expireAfter == -1 {
		return
	}
	if expireAfter == 0 {
		expireAfter = 60	// 1 minute
	}

	for i := -1; i < 10; i++ {
		var analyticsKey string
		if i == -1 {
			//if it's the first iteration, we look for tyk-system-analytics to maintain backwards compatibility or if analytics_config.enable_multiple_analytics_keys is disabled in the gateway
			analyticsKey = analyticsKeyName
		} else {
			analyticsKey = fmt.Sprintf("%v_%v", analyticsKeyName, i)
		}
		exp, _ := r.Store.GetExp(analyticsKey)
		if exp == -1 {
			r.Store.SetExp(analyticsKey, int64(expireAfter))
		}
	}
}

Cognitive complexity: 12, Cyclomatic complexity: 6

Uses: fmt.Sprintf.

func (*RegexExtractor) ExtractAndCheck

func (e *RegexExtractor) ExtractAndCheck(r *http.Request) (SessionID string, returnOverrides ReturnOverrides) {
	if e.IDExtractorConfig.RegexExpression == "" {
		returnOverrides = e.Error(r, nil, "RegexExtractor expects an expression")
		return SessionID, returnOverrides
	}

	var err error
	if e.compiledExpr == nil {
		e.compiledExpr, err = regexp.Compile(e.IDExtractorConfig.RegexExpression)
		if err != nil {
			returnOverrides = e.Error(r, nil, "RegexExtractor found an invalid expression")
			return SessionID, returnOverrides
		}
	}

	var extractorOutput string
	switch e.Config.ExtractFrom {
	case apidef.HeaderSource:
		extractorOutput, err = e.ExtractHeader(r)
	case apidef.BodySource:
		extractorOutput, err = e.ExtractBody(r)
	case apidef.FormSource:
		extractorOutput, err = e.ExtractForm(r, e.IDExtractorConfig.FormParamName)
	}
	if err != nil {
		returnOverrides = e.Error(r, err, "RegexExtractor error")
		return SessionID, returnOverrides
	}

	regexOutput := e.compiledExpr.FindAllString(extractorOutput, -1)
	if e.IDExtractorConfig.RegexMatchIndex > len(regexOutput)-1 {
		returnOverrides = e.Error(r, fmt.Errorf("can't find regexp match group"), "RegexExtractor error")
		return SessionID, returnOverrides
	}

	SessionID = e.GenerateSessionID(regexOutput[e.IDExtractorConfig.RegexMatchIndex], e.BaseMiddleware)
	previousSession, keyExists := e.BaseMiddleware.CheckSessionAndIdentityForValidKey(SessionID, r)
	SessionID = previousSession.KeyID

	if keyExists {
		if previousSession.IdExtractorDeadline > time.Now().Unix() {
			ctxSetSession(r, &previousSession, true, e.Gw.GetConfig().HashKeys)
			returnOverrides = ReturnOverrides{
				ResponseCode: 200,
			}
		}
	}
	return SessionID, returnOverrides
}

Cognitive complexity: 20, Cyclomatic complexity: 12

Uses: apidef.BodySource, apidef.FormSource, apidef.HeaderSource, fmt.Errorf, regexp.Compile, time.Now.

func (*ReloadMachinery) Disable

Disable turns off tracking of reload cycles and queues

func (r *ReloadMachinery) Disable() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.run = true
	r.count = 0
	r.cycles = 0
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ReloadMachinery) Enable

Enable when callled it will allow r to keep track of reload cycles and queues

func (r *ReloadMachinery) Enable() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.run = true
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ReloadMachinery) EnsureQueued

EnsureQueued this will block until any queue happens. It will timeout after 100ms

func (r *ReloadMachinery) EnsureQueued(t *testing.T) {
	t.Helper()
	tick := time.NewTicker(time.Millisecond)
	defer tick.Stop()

	for {
		timeout := time.NewTimer(100 * time.Millisecond)

		select {
		case <-timeout.C:
			t.Fatal("Timedout waiting for reload to be queued")
		case <-tick.C:
			if !timeout.Stop() {
				<-timeout.C
			}
			if r.Queued() {
				return
			}
		}
	}
}

Cognitive complexity: 9, Cyclomatic complexity: 6

Uses: time.Millisecond, time.NewTicker, time.NewTimer.

func (*ReloadMachinery) EnsureReloaded

EnsureReloaded this will block until any reload happens. It will timeout after 200ms

func (r *ReloadMachinery) EnsureReloaded(t *testing.T) {
	t.Helper()

	tick := time.NewTicker(time.Millisecond)
	defer tick.Stop()
	for {
		timeout := time.NewTimer(200 * time.Millisecond)

		select {
		case <-timeout.C:
			t.Fatal("Timedout waiting for reload to be queued")
		case <-tick.C:
			if !timeout.Stop() {
				<-timeout.C
			}
			if r.Reloaded() {
				return
			}
		}
	}
}

Cognitive complexity: 9, Cyclomatic complexity: 6

Uses: time.Millisecond, time.NewTicker, time.NewTimer.

func (*ReloadMachinery) OnQueued

OnQueued is called when a reload has been queued. This increments the queue count

func (r *ReloadMachinery) OnQueued() {
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.run {
		r.count++
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*ReloadMachinery) OnReload

OnReload is called when a reload has been completed. This increments the reload cycles count.

func (r *ReloadMachinery) OnReload() {
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.run {
		r.cycles++
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*ReloadMachinery) Queued

Queued returns true if any queue happened

func (r *ReloadMachinery) Queued() bool {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.count > 0
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ReloadMachinery) ReloadTicker

func (r *ReloadMachinery) ReloadTicker() <-chan time.Time {
	return r.reloadTick
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ReloadMachinery) Reloaded

Reloaded returns true if a read has occurred since r was enabled

func (r *ReloadMachinery) Reloaded() bool {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.cycles > 0
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ReloadMachinery) Reset

Reset sets reloads counts and queues to 0

func (r *ReloadMachinery) Reset() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.count = 0
	r.cycles = 0
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ReloadMachinery) StartTicker

func (r *ReloadMachinery) StartTicker() {
	r.stop = make(chan struct{})
	r.started = true

	go func() {
		for {
			select {
			case <-r.stop:
				return
			default:
				r.Tick()
			}
		}
	}()
}

Cognitive complexity: 6, Cyclomatic complexity: 3

func (*ReloadMachinery) StopTicker

func (r *ReloadMachinery) StopTicker() {
	if r.started {
		close(r.stop)
		r.started = false
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*ReloadMachinery) Tick

Tick triggers reload

func (r *ReloadMachinery) Tick() {
	r.reloadTick <- time.Time{}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: time.Time.

func (*ReloadMachinery) TickOk

TickOk triggers a reload and ensures a queue happened and a reload cycle happens. This will block until all the cases are met.

func (r *ReloadMachinery) TickOk(t *testing.T) {
	t.Helper()

	r.EnsureQueued(t)
	r.Tick()
	r.EnsureReloaded(t)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RequestSigning) EnabledForSpec

func (s *RequestSigning) EnabledForSpec() bool {
	return s.Spec.RequestSigning.IsEnabled
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RequestSigning) Name

func (s *RequestSigning) Name() string {
	return "RequestSigning"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RequestSigning) ProcessRequest

func (s *RequestSigning) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if !s.isRequestSigningConfigValid() {
		log.Error("Fields required for signing the request are missing")
		return errors.New("Fields required for signing the request are missing"), http.StatusInternalServerError
	}

	var algoList []string
	if len(s.Spec.HmacAllowedAlgorithms) > 0 {
		algoList = s.Spec.HmacAllowedAlgorithms
	} else {
		algoList = supportedAlgorithms
	}

	algorithmAllowed := false
	for _, alg := range algoList {
		if alg == s.Spec.RequestSigning.Algorithm {
			algorithmAllowed = true
			break
		}
	}
	if !algorithmAllowed {
		log.WithField("algorithm", s.Spec.RequestSigning.Algorithm).Error("Algorithm not supported")
		return errors.New("Request signing algorithm is not supported"), http.StatusInternalServerError
	}

	headers := generateHeaderList(r, s.Spec.RequestSigning.HeaderList)

	path := s.getRequestPath(r)

	signatureString, err := generateHMACSignatureStringFromRequest(r, headers, path)
	if err != nil {
		log.Error(err)
		return err, http.StatusInternalServerError
	}
	strHeaders := strings.Join(headers, " ")

	var encodedSignature string

	if strings.HasPrefix(s.Spec.RequestSigning.Algorithm, "rsa") {
		if s.Spec.RequestSigning.CertificateId == "" {
			log.Error("CertificateID is empty")
			return errors.New("CertificateID is empty"), http.StatusInternalServerError
		}

		certList := s.Gw.CertificateManager.List([]string{s.Spec.RequestSigning.CertificateId}, certs.CertificatePrivate)
		if len(certList) == 0 || certList[0] == nil {
			log.Error("Certificate not found")
			return errors.New("Certificate not found"), http.StatusInternalServerError
		}
		cert := certList[0]
		rsaKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
		if !ok {
			log.Error("Certificate does not contain RSA private key")
			return errors.New("Certificate does not contain RSA private key"), http.StatusInternalServerError
		}
		encodedSignature, err = generateRSAEncodedSignature(signatureString, rsaKey, s.Spec.RequestSigning.Algorithm)
		if err != nil {
			log.Error("Error while generating signature:", err)
			return err, http.StatusInternalServerError
		}
	} else {
		var err error
		encodedSignature, err = generateHMACEncodedSignature(signatureString, s.Spec.RequestSigning.Secret, s.Spec.RequestSigning.Algorithm)
		if err != nil {
			return err, http.StatusInternalServerError
		}
	}

	//Generate Authorization header
	authHeader := "Signature "
	//Append keyId
	authHeader += "keyId=\"" + s.Spec.RequestSigning.KeyId + "\","
	//Append algorithm
	authHeader += "algorithm=\"" + s.Spec.RequestSigning.Algorithm + "\","
	//Append Headers
	authHeader += "headers=\"" + strHeaders + "\","
	//Append signature
	authHeader += "signature=\"" + encodedSignature + "\""

	if s.Spec.RequestSigning.SignatureHeader != "" {
		r.Header.Set(s.Spec.RequestSigning.SignatureHeader, authHeader)
		log.Debugf("Setting %s headers as =%s", s.Spec.RequestSigning.SignatureHeader, authHeader)
	} else {
		r.Header.Set("Authorization", authHeader)
		log.Debug("Setting Authorization headers as =", authHeader)
	}

	return nil, http.StatusOK
}

Cognitive complexity: 35, Cyclomatic complexity: 15

Uses: certs.CertificatePrivate, errors.New, http.StatusInternalServerError, http.StatusOK, rsa.PrivateKey, strings.HasPrefix, strings.Join.

func (*RequestSizeLimitMiddleware) EnabledForSpec

func (t *RequestSizeLimitMiddleware) EnabledForSpec() bool {
	for _, version := range t.Spec.VersionData.Versions {
		if len(version.ExtendedPaths.SizeLimit) > 0 ||
			(!version.GlobalSizeLimitDisabled && version.GlobalSizeLimit > 0) {
			return true
		}
	}
	return false
}

Cognitive complexity: 5, Cyclomatic complexity: 5

func (*RequestSizeLimitMiddleware) Name

func (t *RequestSizeLimitMiddleware) Name() string {
	return "RequestSizeLimitMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*RequestSizeLimitMiddleware) ProcessRequest

RequestSizeLimit will check a request for maximum request size, this can be a global limit or a matched limit.

func (t *RequestSizeLimitMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	if _, ok := skippedMethods[r.Method]; ok {
		return nil, http.StatusOK
	}

	logger := t.Logger()
	logger.Debug("Request size limiter active")

	vInfo, _ := t.Spec.Version(r)

	logger.Debug("Global limit is: ", vInfo.GlobalSizeLimit)
	// Manage global headers first
	if vInfo.GlobalSizeLimit > 0 {
		logger.Debug("Checking global limit")
		err, code := t.checkRequestLimit(r, vInfo.GlobalSizeLimit)
		// If not OK, block
		if code != http.StatusOK {
			return err, code
		}
	}

	// if there's no paths at all path check
	if len(vInfo.ExtendedPaths.SizeLimit) == 0 {
		return nil, http.StatusOK
	}

	versionPaths := t.Spec.RxPaths[vInfo.Name]

	// If there's a potential match, try to match
	found, meta := t.Spec.CheckSpecMatchesStatus(r, versionPaths, RequestSizeLimit)
	if found {
		logger.Debug("Request size limit matched for this URL, checking...")
		rmeta := meta.(*apidef.RequestSizeMeta)
		return t.checkRequestLimit(r, rmeta.SizeLimit)
	}

	return nil, http.StatusOK
}

Cognitive complexity: 11, Cyclomatic complexity: 6

Uses: apidef.RequestSizeMeta, http.StatusOK.

func (*ResponseCacheMiddleware) Base

func (m *ResponseCacheMiddleware) Base() *BaseTykResponseHandler {
	return &m.BaseTykResponseHandler
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseCacheMiddleware) EnabledForSpec

func (m *ResponseCacheMiddleware) EnabledForSpec() bool {
	return m.Spec.CacheOptions.EnableCache
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseCacheMiddleware) HandleError

func (h *ResponseCacheMiddleware) HandleError(rw http.ResponseWriter, req *http.Request) {
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseCacheMiddleware) HandleResponse

HandleResponse checks if the http.Response argument can be cached and caches it for future requests.

func (m *ResponseCacheMiddleware) HandleResponse(w http.ResponseWriter, res *http.Response, r *http.Request, ses *user.SessionState) error {
	// No cache of empty responses
	if res == nil {
		m.Logger().Warning("Upstream request must have failed, response is empty")
		return nil
	}

	// Skip caching the request if cache disabled
	if !m.EnabledForSpec() {
		return nil
	}

	// Has cache been enabled on the request?
	options := ctxGetCacheOptions(r)
	if options == nil {
		m.Logger().Debug("Request is not cacheable")
		return nil
	}

	cacheThisRequest := true
	cacheTTL := options.timeout

	// make sure the status codes match if specified
	if len(options.cacheOnlyResponseCodes) > 0 {
		foundCode := false
		for _, code := range options.cacheOnlyResponseCodes {
			if code == res.StatusCode {
				foundCode = true
				break
			}
		}
		cacheThisRequest = foundCode
	}

	// Are we using upstream cache control?
	if m.Spec.CacheOptions.EnableUpstreamCacheControl {
		// Do we enable cache for this response?
		if res.Header.Get(upstreamCacheHeader) != "" {
			cacheThisRequest = true
		}

		// Read custom or default cache TTL header name
		cacheTTLHeader := upstreamCacheTTLHeader
		if m.Spec.CacheOptions.CacheControlTTLHeader != "" {
			cacheTTLHeader = m.Spec.CacheOptions.CacheControlTTLHeader
		}

		// Get cache TTL from header
		ttl := res.Header.Get(cacheTTLHeader)
		if ttl != "" {
			if cacheAsInt, err := strconv.Atoi(ttl); err == nil {
				cacheTTL = int64(cacheAsInt)
			}
		}
	}

	var toStore string
	var err error

	if cacheThisRequest {
		res.Body, err = newNopCloserBuffer(res.Body)
		if err != nil {
			m.Logger().WithError(err).Error("error reading cache body")
			return nil
		}

		var wireFormatReq bytes.Buffer
		if err := res.Write(&wireFormatReq); err != nil {
			m.Logger().WithError(err).Error("error encoding cache")
			return nil
		}

		ts := m.getTimeTTL(cacheTTL)
		toStore = m.encodePayload(wireFormatReq.String(), ts)

		go func() {
			err := m.store.SetKey(options.key, toStore, cacheTTL)
			if err != nil {
				m.Logger().WithError(err).Error("could not save key in cache store")
			}
		}()
	}

	/*
		m.Logger().
			WithError(err).
			WithField("cache", cacheThisRequest).
			WithField("stored", toStore).
			WithField("key", options.key).
			Debug("Done response cache")
	*/

	return nil
}

Cognitive complexity: 32, Cyclomatic complexity: 16

Uses: bytes.Buffer, strconv.Atoi.

func (*ResponseCacheMiddleware) Init

func (h *ResponseCacheMiddleware) Init(c interface{}, spec *APISpec) error {
	h.Spec = spec
	return nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*ResponseCacheMiddleware) Logger

func (m *ResponseCacheMiddleware) Logger() *logrus.Entry {
	return log.WithField("mw", m.Name())
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseCacheMiddleware) Name

func (m *ResponseCacheMiddleware) Name() string {
	return "ResponseCacheMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseGoPluginMiddleware) HandleError

func (h *ResponseGoPluginMiddleware) HandleError(rw http.ResponseWriter, req *http.Request) {
	//noop
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseGoPluginMiddleware) HandleGoPluginResponse

func (h *ResponseGoPluginMiddleware) HandleGoPluginResponse(w http.ResponseWriter, res *http.Response, req *http.Request) error {
	// make sure tyk recover in case Go-plugin function panics
	defer func() {
		if e := recover(); e != nil {
			err := fmt.Errorf("%v", e)
			w.WriteHeader(http.StatusInternalServerError)
			h.logger.WithError(err).Error("Recovered from panic while running Go-plugin middleware func")

		}
	}()

	// Inject definition into response context
	h.Spec.injectIntoReqContext(req)

	// wrap ResponseWriter to check if response was sent
	rw := &customResponseWriter{
		ResponseWriter:	w,
		copyData:	recordDetail(req, h.Spec),
	}

	// call Go-plugin function
	t1 := time.Now()

	h.ResHandler(rw, res, req)

	// calculate latency
	ms := DurationToMillisecond(time.Since(t1))
	h.logger.WithField("ms", ms).Debug("Go-plugin response processing took")

	// check if response was sent
	if rw.responseSent {
		// check if response code was an error one

		if rw.statusCodeSent >= http.StatusBadRequest {
			// base middleware will report this error to analytics if needed
			w.WriteHeader(rw.statusCodeSent)
			err := fmt.Errorf("plugin function sent error response code: %d", rw.statusCodeSent)
			h.logger.WithError(err).Error("Returned error code while processing response with Go-plugin middleware func")
			return err
		}
	}
	return nil
}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: fmt.Errorf, http.StatusBadRequest, http.StatusInternalServerError, time.Now, time.Since.

func (*ResponseGoPluginMiddleware) HandleResponse

func (h *ResponseGoPluginMiddleware) HandleResponse(w http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error {
	err := h.HandleGoPluginResponse(w, res, req)
	if err != nil {
		return err
	}

	return nil
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*ResponseGoPluginMiddleware) Init

func (h *ResponseGoPluginMiddleware) Init(c interface{}, spec *APISpec) error {
	h.Spec = spec
	h.Path = c.(apidef.MiddlewareDefinition).Path
	h.SymbolName = c.(apidef.MiddlewareDefinition).Name

	h.logger = log.WithFields(logrus.Fields{
		"mwPath":	h.Path,
		"mwSymbolName":	h.SymbolName,
	})

	if h.ResHandler != nil {
		h.logger.Info("Go-plugin middleware is already initialized")
		// noop
		return nil
	}

	newPath, err := goplugin.GetPluginFileNameToLoad(goplugin.FileSystemStorage{}, h.Path)
	if err != nil {
		h.logger.WithError(err).Error("Could not load Go-plugin. File was not found")
		return err
	}
	if h.Path != newPath {
		h.Path = newPath
	}

	// try to load plugin
	if h.ResHandler, err = goplugin.GetResponseHandler(h.Path, h.SymbolName); err != nil {
		h.logger.WithError(err).Error("Could not load Go-plugin")
		return err
	}
	h.logger.Infof("Loaded Go response plugin: %s", h.SymbolName)

	return nil
}

Cognitive complexity: 11, Cyclomatic complexity: 5

Uses: apidef.MiddlewareDefinition, goplugin.FileSystemStorage, goplugin.GetPluginFileNameToLoad, goplugin.GetResponseHandler, logrus.Fields.

func (*ResponseTransformJQMiddleware) HandleError

func (h *ResponseTransformJQMiddleware) HandleError(rw http.ResponseWriter, req *http.Request) {
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseTransformJQMiddleware) HandleResponse

func (h *ResponseTransformJQMiddleware) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error {
	log.Warning("JQ transforms not supported")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseTransformJQMiddleware) Init

func (h *ResponseTransformJQMiddleware) Init(c interface{}, spec *APISpec) error {
	h.Spec = spec

	return nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*ResponseTransformMiddleware) Base

func (r *ResponseTransformMiddleware) Base() *BaseTykResponseHandler {
	return &r.BaseTykResponseHandler
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseTransformMiddleware) Enabled

func (r *ResponseTransformMiddleware) Enabled() bool {
	for _, version := range r.Spec.VersionData.Versions {
		if len(version.ExtendedPaths.TransformResponse) > 0 {
			for _, transformResponse := range version.ExtendedPaths.TransformResponse {
				if !transformResponse.Disabled {
					return true
				}
			}
		}
	}
	return false
}

Cognitive complexity: 10, Cyclomatic complexity: 5

func (*ResponseTransformMiddleware) HandleError

func (r *ResponseTransformMiddleware) HandleError(rw http.ResponseWriter, req *http.Request) {
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ResponseTransformMiddleware) HandleResponse

func (r *ResponseTransformMiddleware) HandleResponse(rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error {
	logger := log.WithFields(logrus.Fields{
		"prefix":	"outbound-transform",
		"server_name":	r.Spec.Proxy.TargetURL,
		"api_id":	r.Spec.APIID,
		"path":		req.URL.Path,
	})

	versionInfo, _ := r.Spec.Version(req)
	versionPaths := r.Spec.RxPaths[versionInfo.Name]
	found, meta := r.Spec.CheckSpecMatchesStatus(req, versionPaths, TransformedResponse)
	if !found {
		return nil
	}
	tmeta := meta.(*TransformSpec)

	respBody := respBodyReader(req, res)
	body, _ := ioutil.ReadAll(respBody)
	defer respBody.Close()

	// Put into an interface:
	bodyData := make(map[string]interface{})
	switch tmeta.TemplateData.Input {
	case apidef.RequestXML:
		if len(body) == 0 {
			body = []byte("<_/>")
		}

		mxj.XmlCharsetReader = WrappedCharsetReader
		var err error

		xmlMap, err := mxj.NewMapXml(body)	// unmarshal
		if err != nil {
			logger.WithError(err).Error("Error unmarshalling XML")
			//todo return error
			break
		}
		for k, v := range xmlMap {
			bodyData[k] = v
		}
	default:	// apidef.RequestJSON
		if len(body) == 0 {
			body = []byte("{}")
		}

		var tempBody interface{}
		if err := json.Unmarshal(body, &tempBody); err != nil {
			logger.WithError(err).Error("Error unmarshalling JSON")
			//todo return error
			break
		}

		switch tempBody.(type) {
		case []interface{}:
			bodyData["array"] = tempBody
		case map[string]interface{}:
			bodyData = tempBody.(map[string]interface{})
		}
	}

	if r.Spec.EnableContextVars {
		bodyData["_tyk_context"] = ctxGetData(req)
	}

	if tmeta.TemplateData.EnableSession {
		if session := ctxGetSession(req); session != nil {
			bodyData["_tyk_meta"] = session.MetaData
		} else {
			logger.Error("Session context was enabled but not found.")
		}
	}

	// Apply to template
	var bodyBuffer bytes.Buffer
	if err := tmeta.Template.Execute(&bodyBuffer, bodyData); err != nil {
		logger.WithError(err).Error("Failed to apply template to request")
	}

	// Re-compress if original upstream response was compressed
	encoding := res.Header.Get("Content-Encoding")
	bodyBuffer = compressBuffer(bodyBuffer, encoding)

	res.ContentLength = int64(bodyBuffer.Len())
	res.Header.Set("Content-Length", strconv.Itoa(bodyBuffer.Len()))
	res.Body = ioutil.NopCloser(&bodyBuffer)

	return nil
}

Cognitive complexity: 36, Cyclomatic complexity: 16

Uses: apidef.RequestXML, bytes.Buffer, ioutil.NopCloser, ioutil.ReadAll, json.Unmarshal, logrus.Fields, mxj.NewMapXml, mxj.XmlCharsetReader, strconv.Itoa.

func (*ResponseTransformMiddleware) Init

func (r *ResponseTransformMiddleware) Init(c interface{}, spec *APISpec) error {
	r.Spec = spec
	return nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*ResponseTransformMiddleware) Name

func (r *ResponseTransformMiddleware) Name() string {
	return "ResponseTransformMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ReverseProxy) CheckCircuitBreakerEnforced

func (p *ReverseProxy) CheckCircuitBreakerEnforced(spec *APISpec, req *http.Request) (bool, *ExtendedCircuitBreakerMeta) {
	if !spec.CircuitBreakerEnabled {
		return false, nil
	}

	versionInfo, _ := spec.Version(req)
	versionPaths := spec.RxPaths[versionInfo.Name]
	found, meta := spec.CheckSpecMatchesStatus(req, versionPaths, CircuitBreaker)
	if found {
		exMeta := meta.(*ExtendedCircuitBreakerMeta)
		p.logger.Debug("CB Enforced for path: ", *exMeta)
		return true, exMeta
	}

	return false, nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

func (*ReverseProxy) CheckHardTimeoutEnforced

CheckHardTimeoutEnforced checks APISpec versions for a fine grained timeout value. The value is defined in seconds, but we're using float64 to enable sub-second durations for tests. Changing to int would break that behaviour.

func (p *ReverseProxy) CheckHardTimeoutEnforced(spec *APISpec, req *http.Request) (bool, float64) {
	if !spec.EnforcedTimeoutEnabled {
		return false, 0
	}

	vInfo, _ := spec.Version(req)
	versionPaths := spec.RxPaths[vInfo.Name]
	found, meta := spec.CheckSpecMatchesStatus(req, versionPaths, HardTimeout)
	if found {
		intMeta, ok := meta.(*int)
		if ok && *intMeta > 0 {
			p.logger.Debug("HARD TIMEOUT ENFORCED: ", *intMeta)
			return true, float64(*intMeta)
		}
	}

	return false, 0
}

Cognitive complexity: 6, Cyclomatic complexity: 5

func (*ReverseProxy) CheckHeaderInRemoveList

func (p *ReverseProxy) CheckHeaderInRemoveList(hdr string, spec *APISpec, req *http.Request) bool {
	vInfo, _ := spec.Version(req)
	versionPaths := spec.RxPaths[vInfo.Name]
	for _, gdKey := range vInfo.GlobalHeadersRemove {
		if strings.ToLower(gdKey) == strings.ToLower(hdr) {
			return true
		}
	}

	// Check path config
	if found, meta := spec.CheckSpecMatchesStatus(req, versionPaths, HeaderInjected); found {
		hmeta := meta.(*apidef.HeaderInjectionMeta)
		for _, gdKey := range hmeta.DeleteHeaders {
			if strings.ToLower(gdKey) == strings.ToLower(hdr) {
				return true
			}
		}
	}

	return false
}

Cognitive complexity: 12, Cyclomatic complexity: 6

Uses: apidef.HeaderInjectionMeta, strings.ToLower.

func (*ReverseProxy) CopyResponse

func (p *ReverseProxy) CopyResponse(dst io.Writer, src io.Reader, flushInterval time.Duration) {

	if flushInterval != 0 {
		if wf, ok := dst.(writeFlusher); ok {
			mlw := &maxLatencyWriter{
				dst:		wf,
				latency:	flushInterval,
			}
			defer mlw.stop()

			// set up initial timer so headers get flushed even if body writes are delayed
			mlw.flushPending = true
			mlw.t = time.AfterFunc(flushInterval, mlw.delayedFlush)

			dst = mlw
		}
	}

	p.copyBuffer(dst, src)
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: time.AfterFunc.

func (*ReverseProxy) HandleResponse

func (p *ReverseProxy) HandleResponse(rw http.ResponseWriter, res *http.Response, ses *user.SessionState) error {
	// Remove hop-by-hop headers listed in the
	// "Connection" header of the response.
	if c := res.Header.Get(header.Connection); c != "" {
		for _, f := range strings.Split(c, ",") {
			if f = strings.TrimSpace(f); f != "" {
				res.Header.Del(f)
			}
		}
	}

	for _, h := range hopHeaders {
		res.Header.Del(h)
	}
	defer res.Body.Close()

	// Close connections
	if p.Gw.GetConfig().CloseConnections {
		res.Header.Set(header.Connection, "close")
	}

	// Add resource headers
	if ses != nil {
		// We have found a session, lets report back
		quotaMax, quotaRemaining, _, quotaRenews := ses.GetQuotaLimitByAPIID(p.TykAPISpec.APIID)
		res.Header.Set(header.XRateLimitLimit, strconv.Itoa(int(quotaMax)))
		res.Header.Set(header.XRateLimitRemaining, strconv.Itoa(int(quotaRemaining)))
		res.Header.Set(header.XRateLimitReset, strconv.Itoa(int(quotaRenews)))
	}

	copyHeader(rw.Header(), res.Header, p.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey)

	announcedTrailers := len(res.Trailer)
	if announcedTrailers > 0 {
		trailerKeys := make([]string, 0, len(res.Trailer))
		for k := range res.Trailer {
			trailerKeys = append(trailerKeys, k)
		}
		rw.Header().Add("Trailer", strings.Join(trailerKeys, ", "))
	}

	// do not write on a hijacked connection
	if res.StatusCode != http.StatusSwitchingProtocols {
		rw.WriteHeader(res.StatusCode)
	}

	if len(res.Trailer) > 0 {
		// Force chunking if we saw a response trailer.
		// This prevents net/http from calculating the length for short
		// bodies and adding a Content-Length.
		if fl, ok := rw.(http.Flusher); ok {
			fl.Flush()
		}
	}

	p.CopyResponse(rw, res.Body, p.flushInterval(res))

	if len(res.Trailer) == announcedTrailers {
		copyHeader(rw.Header(), res.Trailer, p.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey)
		return nil
	}

	for k, vv := range res.Trailer {
		k = http.TrailerPrefix + k
		for _, v := range vv {
			rw.Header().Add(k, v)
		}
	}
	return nil
}

Cognitive complexity: 33, Cyclomatic complexity: 15

Uses: header.Connection, header.XRateLimitLimit, header.XRateLimitRemaining, header.XRateLimitReset, http.Flusher, http.StatusSwitchingProtocols, http.TrailerPrefix, strconv.Itoa, strings.Join, strings.Split, strings.TrimSpace.

func (*ReverseProxy) IsUpgrade

IsUpgrade will return the upgrade header value and true if present for the request. It requires EnableWebSockets to be enabled in the gateway HTTP server config.

func (p *ReverseProxy) IsUpgrade(req *http.Request) (string, bool) {
	if !p.Gw.GetConfig().HttpServerOptions.EnableWebSockets {
		return "", false
	}

	return httputil.IsUpgrade(req)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: httputil.IsUpgrade.

func (*ReverseProxy) ServeHTTP

func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) ProxyResponse {
	startTime := time.Now()
	p.logger.WithField("ts", startTime.UnixNano()).Debug("Started")

	resp := p.WrappedServeHTTP(rw, req, recordDetail(req, p.TykAPISpec))

	finishTime := time.Since(startTime)
	p.logger.WithField("ns", finishTime.Nanoseconds()).Debug("Finished")

	// make response body to be nopCloser and re-readable before serve it through chain of middlewares
	nopCloseResponseBody(resp.Response)

	return resp
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: time.Now, time.Since.

func (*ReverseProxy) ServeHTTPForCache

func (p *ReverseProxy) ServeHTTPForCache(rw http.ResponseWriter, req *http.Request) ProxyResponse {
	startTime := time.Now()
	p.logger.WithField("ts", startTime.UnixNano()).Debug("Started")

	resp := p.WrappedServeHTTP(rw, req, true)
	nopCloseResponseBody(resp.Response)
	finishTime := time.Since(startTime)
	p.logger.WithField("ns", finishTime.Nanoseconds()).Debug("Finished")

	return resp
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: time.Now, time.Since.

func (*ReverseProxy) WrappedServeHTTP

func (p *ReverseProxy) WrappedServeHTTP(rw http.ResponseWriter, req *http.Request, withCache bool) ProxyResponse {
	if trace.IsEnabled() {
		span, ctx := trace.Span(req.Context(), req.URL.Path)
		defer span.Finish()
		ext.SpanKindRPCClient.Set(span)
		req = req.WithContext(ctx)
	}
	var roundTripper *TykRoundTripper

	reqCtx := req.Context()
	if cn, ok := rw.(http.CloseNotifier); ok {
		var cancel context.CancelFunc
		reqCtx, cancel = context.WithCancel(reqCtx)
		defer cancel()
		notifyChan := cn.CloseNotify()
		go func() {
			select {
			case <-notifyChan:
				cancel()
			case <-reqCtx.Done():
			}
		}()
	}

	// Do this before we make a shallow copy
	session := ctxGetSession(req)

	outreq := new(http.Request)
	logreq := new(http.Request)

	*outreq = *req	// includes shallow copies of maps, but okay
	*logreq = *req

	deepCopyErr := deepCopyBody(req, outreq)
	if deepCopyErr != nil {
		p.logger.Debug("Unable to create deep copy of request, err: ", deepCopyErr)
		p.ErrorHandler.HandleError(rw, logreq, "There was a problem with reading Body of the Request.",
			http.StatusInternalServerError, true)
		return ProxyResponse{}
	}

	// remove context data from the copies
	setContext(outreq, context.Background())
	setContext(logreq, context.Background())

	p.logger.Debug("Upstream request URL: ", req.URL)

	// We need to double set the context for the outbound request to reprocess the target
	if p.TykAPISpec.URLRewriteEnabled && req.Context().Value(ctx.RetainHost) == true {
		p.logger.Debug("Detected host rewrite, notifying director")
		setCtxValue(outreq, ctx.RetainHost, true)
	}

	if req.ContentLength == 0 {
		outreq.Body = nil	// Issue 16036: nil Body for http.Transport retries
	}
	outreq = outreq.WithContext(reqCtx)
	setContext(logreq, outreq.Context())

	outreq.Header = cloneHeader(req.Header)
	if trace.IsEnabled() {
		span := opentracing.SpanFromContext(req.Context())
		trace.Inject(p.TykAPISpec.Name, span, outreq.Header)
	}
	p.Director(outreq)
	outreq.Close = false

	p.logger.Debug("Outbound request URL: ", outreq.URL.String())

	reqUpType, outReqUpgrade := p.IsUpgrade(req)

	// See RFC 2616, section 14.10.
	if c := outreq.Header.Get("Connection"); c != "" {
		for _, f := range strings.Split(c, ",") {
			if f = strings.TrimSpace(f); f != "" {
				outreq.Header.Del(f)
			}
		}
	}
	// Remove other hop-by-hop headers to the backend. Especially
	// important is "Connection" because we want a persistent
	// connection, regardless of what the client sent to us.
	for _, h := range hopHeaders {
		hv := outreq.Header.Get(h)
		if hv == "" {
			continue
		}
		if h == "Te" && hv == "trailers" {
			continue
		}
		outreq.Header.Del(h)
		logreq.Header.Del(h)
	}

	if outReqUpgrade {
		outreq.Header.Set("Connection", "Upgrade")
		logreq.Header.Set("Connection", "Upgrade")
		outreq.Header.Set("Upgrade", reqUpType)
		logreq.Header.Set("Upgrade", reqUpType)
	}

	addrs := requestIPHops(req)
	if !p.CheckHeaderInRemoveList(header.XForwardFor, p.TykAPISpec, req) {
		outreq.Header.Set(header.XForwardFor, addrs)
	}

	// Circuit breaker
	breakerEnforced, breakerConf := p.CheckCircuitBreakerEnforced(p.TykAPISpec, req)

	// set up TLS certificates for upstream if needed
	var tlsCertificates []tls.Certificate
	if cert := p.Gw.getUpstreamCertificate(outreq.URL.Host, p.TykAPISpec); cert != nil {
		p.logger.Debug("Found upstream mutual TLS certificate")
		tlsCertificates = []tls.Certificate{*cert}
	}

	p.TykAPISpec.Lock()

	isTimeoutEnforced, enforcedTimeout := p.CheckHardTimeoutEnforced(p.TykAPISpec, outreq)

	// limit request time with context timeout
	if isTimeoutEnforced {
		timeoutContext, cancel := context.WithTimeout(outreq.Context(), time.Duration(enforcedTimeout)*time.Second)
		defer cancel()

		outreq = outreq.WithContext(timeoutContext)
	}

	// create HTTP transport
	createTransport := p.TykAPISpec.HTTPTransport == nil

	// Check if timeouts are set for this endpoint
	if !createTransport && p.Gw.GetConfig().MaxConnTime != 0 {
		createTransport = time.Since(p.TykAPISpec.HTTPTransportCreated) > time.Duration(p.Gw.GetConfig().MaxConnTime)*time.Second
	}

	if createTransport {
		var oldTransport *http.Transport

		if p.TykAPISpec.HTTPTransport != nil {
			oldTransport = p.TykAPISpec.HTTPTransport.transport
			// Prevent new idle connections to be generated.
			oldTransport.DisableKeepAlives = true
		}

		timeout := proxyTimeout(p.TykAPISpec)

		// If an enforced timeout is configured for this API endpoint, use it instead
		// of the global default timeout, as it should take precedence
		if isTimeoutEnforced {
			timeout = enforcedTimeout
		}

		p.TykAPISpec.HTTPTransport = p.httpTransport(timeout, rw, req, outreq)
		p.TykAPISpec.HTTPTransportCreated = time.Now()

		if oldTransport != nil {
			oldTransport.CloseIdleConnections()
		}
	}

	roundTripper = p.TykAPISpec.HTTPTransport

	if roundTripper.transport != nil {
		roundTripper.transport.TLSClientConfig.Certificates = tlsCertificates
	}
	p.TykAPISpec.Unlock()

	if outreq.URL.Scheme == "h2c" {
		outreq.URL.Scheme = "http"
	}

	if p.TykAPISpec.Proxy.Transport.SSLForceCommonNameCheck || p.Gw.GetConfig().SSLForceCommonNameCheck {
		// if proxy is enabled, add CommonName verification in verifyPeerCertificate
		// DialTLS is not executed if proxy is used
		httpTransport := roundTripper.transport

		p.logger.Debug("Using forced SSL CN check")

		if proxyURL, _ := httpTransport.Proxy(req); proxyURL != nil {
			p.logger.Debug("Detected proxy: " + proxyURL.String())
			tlsConfig := httpTransport.TLSClientConfig
			host, _, _ := net.SplitHostPort(outreq.Host)
			p.setCommonNameVerifyPeerCertificate(tlsConfig, host)
		}

	}

	p.addAuthInfo(outreq, req)

	// do request round trip
	var (
		res		*http.Response
		isHijacked	bool
		upstreamLatency	time.Duration
		err		error
	)

	if breakerEnforced {
		if !breakerConf.CB.Ready() {
			p.logger.Debug("ON REQUEST: Circuit Breaker is in OPEN state")
			p.ErrorHandler.HandleError(rw, logreq, "Service temporarily unavailable.", 503, true)
			return ProxyResponse{}
		}
		p.logger.Debug("ON REQUEST: Circuit Breaker is in CLOSED or HALF-OPEN state")

		res, isHijacked, upstreamLatency, err = p.handleOutboundRequest(roundTripper, outreq, rw)
		if err != nil || res.StatusCode/100 == 5 {
			breakerConf.CB.Fail()
		} else {
			breakerConf.CB.Success()
		}
	} else {
		res, isHijacked, upstreamLatency, err = p.handleOutboundRequest(roundTripper, outreq, rw)
	}

	if err != nil {
		token := ctxGetAuthToken(req)

		var alias string
		if session != nil {
			alias = session.Alias
		}

		p.logger.WithFields(logrus.Fields{
			"prefix":	"proxy",
			"user_ip":	addrs,
			"server_name":	outreq.Host,
			"user_id":	p.Gw.obfuscateKey(token),
			"user_name":	alias,
			"org_id":	p.TykAPISpec.OrgID,
			"api_id":	p.TykAPISpec.APIID,
		}).Error("http: proxy error: ", err)

		if strings.HasPrefix(err.Error(), "mock:") {
			p.ErrorHandler.HandleError(rw, logreq, err.Error(), res.StatusCode, true)
			return ProxyResponse{UpstreamLatency: upstreamLatency}
		}

		if strings.Contains(err.Error(), "timeout awaiting response headers") || strings.Contains(err.Error(), "context deadline exceeded") {
			p.ErrorHandler.HandleError(rw, logreq, "Upstream service reached hard timeout.", http.StatusGatewayTimeout, true)

			if p.TykAPISpec.Proxy.ServiceDiscovery.UseDiscoveryService {
				p.logger.Debug("[PROXY] [SERVICE DISCOVERY] Upstream host failed, refreshing host list")
				p.Gw.ServiceCache.Delete(p.TykAPISpec.APIID)
			}
			return ProxyResponse{UpstreamLatency: upstreamLatency}
		}

		if strings.Contains(err.Error(), "context canceled") {
			p.ErrorHandler.HandleError(rw, logreq, "Client closed request", 499, true)
			return ProxyResponse{UpstreamLatency: upstreamLatency}
		}

		if strings.Contains(err.Error(), "no such host") {
			p.ErrorHandler.HandleError(rw, logreq, "Upstream host lookup failed", http.StatusInternalServerError, true)
			return ProxyResponse{UpstreamLatency: upstreamLatency}
		}
		p.ErrorHandler.HandleError(rw, logreq, "There was a problem proxying the request", http.StatusInternalServerError, true)
		return ProxyResponse{UpstreamLatency: upstreamLatency}

	}

	if isHijacked {
		return ProxyResponse{UpstreamLatency: upstreamLatency}
	}

	_, upgrade := p.IsUpgrade(req)
	// Deal with 101 Switching Protocols responses: (WebSocket, h2c, etc)
	if upgrade && res.StatusCode == 101 {
		if err := p.handleUpgradeResponse(rw, outreq, res); err != nil {
			p.ErrorHandler.HandleError(rw, logreq, err.Error(), http.StatusInternalServerError, true)
			return ProxyResponse{UpstreamLatency: upstreamLatency}
		}
	}

	ses := new(user.SessionState)
	if session != nil {
		ses = session
	}

	// Middleware chain handling here - very simple, but should do
	// the trick. Chain can be empty, in which case this is a no-op.
	// abortRequest is set to true when a response hook fails
	// For reference see "HandleError" in coprocess.go
	abortRequest, err := handleResponseChain(p.TykAPISpec.ResponseChain, rw, res, req, ses)
	if abortRequest {
		return ProxyResponse{UpstreamLatency: upstreamLatency}
	}

	if err != nil {
		p.logger.Error("Response chain failed! ", err)
	}

	inres := new(http.Response)

	if httputil.IsStreamingRequest(req) || httputil.IsStreamingResponse(res) {
		withCache = false
	}

	if withCache {
		*inres = *res	// includes shallow copies of maps, but okay

		if !upgrade {
			defer res.Body.Close()

			// Buffer body data
			var bodyBuffer bytes.Buffer
			bodyBuffer2 := new(bytes.Buffer)

			p.CopyResponse(&bodyBuffer, res.Body, p.flushInterval(res))
			*bodyBuffer2 = bodyBuffer

			// Create new ReadClosers so we can split output
			res.Body = ioutil.NopCloser(&bodyBuffer)
			inres.Body = ioutil.NopCloser(bodyBuffer2)
		}
	}

	// We should at least copy the status code in
	inres.StatusCode = res.StatusCode
	inres.ContentLength = res.ContentLength
	p.HandleResponse(rw, res, ses)
	return ProxyResponse{UpstreamLatency: upstreamLatency, Response: inres}
}

Cognitive complexity: 111, Cyclomatic complexity: 55

Uses: bytes.Buffer, context.Background, context.CancelFunc, context.WithCancel, context.WithTimeout, ctx.RetainHost, ext.SpanKindRPCClient, header.XForwardFor, http.CloseNotifier, http.Request, http.Response, http.StatusGatewayTimeout, http.StatusInternalServerError, http.Transport, httputil.IsStreamingRequest, httputil.IsStreamingResponse, ioutil.NopCloser, logrus.Fields, net.SplitHostPort, strings.Contains, strings.HasPrefix, strings.Split, strings.TrimSpace, time.Duration, time.Now, time.Second, time.Since, tls.Certificate, trace.Inject, trace.IsEnabled, trace.Span, user.SessionState.

func (*RoundRobin) WithLen

func (r *RoundRobin) WithLen(len int) int {
	if len < 1 {
		return 0
	}
	// -1 to start at 0, not 1
	cur := atomic.AddUint32(&r.pos, 1) - 1
	return int(cur) % len
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: atomic.AddUint32.

func (*ServiceDiscovery) Hostname

func (s *ServiceDiscovery) Hostname(item *gabs.Container) string {
	var hostname string
	// Get a nested object
	if s.isNested {
		hostname = s.NestedObject(item)
	} else {
		hostname = s.Object(item)
	}
	return hostname
}

Cognitive complexity: 4, Cyclomatic complexity: 2

func (*ServiceDiscovery) Init

func (s *ServiceDiscovery) Init(spec *apidef.ServiceDiscoveryConfiguration) {
	s.spec = spec
	s.isNested = spec.UseNestedQuery
	s.isTargetList = spec.UseTargetList
	s.endpointReturnsList = spec.EndpointReturnsList
	s.targetPath = spec.TargetPath

	if spec.PortDataPath != "" {
		s.portSeperate = true
		s.portPath = spec.PortDataPath
	}

	if spec.ParentDataPath != "" {
		s.parentPath = spec.ParentDataPath
	}

	s.dataPath = spec.DataPath
}

Cognitive complexity: 4, Cyclomatic complexity: 3

func (*ServiceDiscovery) NestedObject

func (s *ServiceDiscovery) NestedObject(item *gabs.Container) string {
	parentData := s.decodeToNameSpace(s.parentPath, item)
	// Get the data path from the decoded object
	subContainer := gabs.Container{}
	switch x := parentData.(type) {
	case string:
		s.ParseObject(x, &subContainer)
	default:
		log.Debug("Get Nested Object: parentData is not a string")
		return ""
	}
	return s.Object(&subContainer)
}

Cognitive complexity: 4, Cyclomatic complexity: 3

func (*ServiceDiscovery) Object

func (s *ServiceDiscovery) Object(item *gabs.Container) string {
	hostnameData := s.decodeToNameSpace(s.dataPath, item)
	if str, ok := hostnameData.(string); ok {
		// Get the port
		str = s.addPortFromObject(str, item)
		return str
	}
	log.Warning("Get Object: hostname is not a string")
	return ""
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*ServiceDiscovery) ParseObject

func (s *ServiceDiscovery) ParseObject(contents string, jsonParsed *gabs.Container) error {
	log.Debug("Parsing raw data: ", contents)
	jp, err := gabs.ParseJSON([]byte(contents))
	if err != nil {
		log.Error(err)
		return err
	}
	*jsonParsed = *jp
	log.Debug("Got:", jsonParsed)
	return nil
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*ServiceDiscovery) ProcessRawData

func (s *ServiceDiscovery) ProcessRawData(rawData string) (*apidef.HostList, error) {
	var jsonParsed gabs.Container

	hostlist := apidef.NewHostList()

	if s.endpointReturnsList {
		// Convert to an object
		jsonData := s.rawListToObj(rawData)
		if err := s.ParseObject(jsonData, &jsonParsed); err != nil {
			log.Error("Parse object failed: ", err)
			return nil, err
		}

		log.Debug("Parsed object list: ", jsonParsed)
		// Treat JSON as a list and then apply the data path
		if s.isTargetList {
			// Get all values
			asList := s.SubObjectFromList(&jsonParsed)
			log.Debug("Host list:", asList)
			hostlist.Set(asList)
			return hostlist, nil
		}

		// Get the top value
		list := s.SubObjectFromList(&jsonParsed)
		var host string
		for _, v := range list {
			host = v
			break
		}

		hostlist.Set([]string{host})
		return hostlist, nil
	}

	// It's an object
	s.ParseObject(rawData, &jsonParsed)
	if s.isTargetList {
		// It's a list object
		log.Debug("It's a target list - getting sub object from list")
		log.Debug("Passing in: ", jsonParsed)

		asList := s.SubObjectFromList(&jsonParsed)
		hostlist.Set(asList)
		log.Debug("Got from object: ", hostlist)
		return hostlist, nil
	}

	// It's a single object
	host := s.SubObject(&jsonParsed)
	hostlist.Set([]string{host})

	return hostlist, nil
}

Cognitive complexity: 13, Cyclomatic complexity: 6

Uses: apidef.NewHostList.

func (*ServiceDiscovery) SubObject

func (s *ServiceDiscovery) SubObject(obj *gabs.Container) string {
	return s.Hostname(obj) + s.targetPath
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ServiceDiscovery) SubObjectFromList

func (s *ServiceDiscovery) SubObjectFromList(objList *gabs.Container) []string {
	hostList := []string{}
	var hostname string
	var set []*gabs.Container
	if s.endpointReturnsList {
		// pre-process the object since we've nested it
		set = s.decodeToNameSpaceAsArray(arrayName, objList)
		log.Debug("set: ", set)
	} else if s.isNested {	// It's an object, but the value may be nested
		// Get the actual raw string object
		parentData := s.decodeToNameSpace(s.parentPath, objList)
		// Get the data path from the decoded object
		subContainer := gabs.Container{}

		// Now check if this string is a list
		nestedString, ok := parentData.(string)
		if !ok {
			log.Debug("parentData is not a string")
			return hostList
		}
		if s.isList(nestedString) {
			log.Debug("Yup, it's a list")
			jsonData := s.rawListToObj(nestedString)
			s.ParseObject(jsonData, &subContainer)
			set = s.decodeToNameSpaceAsArray(arrayName, &subContainer)

			// Hijack this here because we need to use a non-nested get
			for _, item := range set {
				log.Debug("Child in list: ", item)
				hostname = s.Object(item) + s.targetPath
				// Add to list
				hostList = append(hostList, hostname)
			}
			return hostList
		}
		log.Debug("Not a list")
		s.ParseObject(nestedString, &subContainer)
		set = s.decodeToNameSpaceAsArray(s.dataPath, objList)
		log.Debug("set (object list): ", objList)
	} else if s.parentPath != "" {
		set = s.decodeToNameSpaceAsArray(s.parentPath, objList)
	}

	for _, item := range set {
		log.Debug("Child in list: ", item)
		hostname = s.Hostname(item) + s.targetPath
		// Add to list
		hostList = append(hostList, hostname)
	}
	return hostList
}

Cognitive complexity: 18, Cyclomatic complexity: 8

func (*ServiceDiscovery) Target

func (s *ServiceDiscovery) Target(serviceURL string) (*apidef.HostList, error) {
	// Get the data
	rawData, err := s.getServiceData(serviceURL)
	if err != nil {
		return nil, err
	}

	return s.ProcessRawData(rawData)

}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*SessionLimiter) Context

func (l *SessionLimiter) Context() context.Context {
	return l.ctx
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*SessionLimiter) ForwardMessage

ForwardMessage will enforce rate limiting, returning a non-zero sessionFailReason if session limits have been exceeded. Key values to manage rate are Rate and Per, e.g. Rate of 10 messages Per 10 seconds

func (l *SessionLimiter) ForwardMessage(r *http.Request, session *user.SessionState, rateLimitKey string, quotaKey string, store storage.Handler, enableRL, enableQ bool, api *APISpec, dryRun bool) sessionFailReason {
	// check for limit on API level (set to session by ApplyPolicies)
	accessDef, allowanceScope, err := GetAccessDefinitionByAPIIDOrSession(session, api)
	if err != nil {
		log.WithField("apiID", api.APIID).Debugf("[RATE] %s", err.Error())
		return sessionFailRateLimit
	}

	var (
		apiLimit		= accessDef.Limit.Clone()
		endpointRLKeySuffix	= ""
	)

	endpointRLInfo, doEndpointRL := l.RateLimitInfo(r, api, accessDef.Endpoints)
	if doEndpointRL {
		apiLimit.Rate = endpointRLInfo.Rate
		apiLimit.Per = endpointRLInfo.Per
		endpointRLKeySuffix = endpointRLInfo.KeySuffix
	}

	// If quotaKey is not set then the default ratelimit keys should be used.
	useCustomKey := quotaKey != ""

	// If rate is -1 or 0, it means unlimited and no need for rate limiting.
	if enableRL && apiLimit.Rate > 0 {
		log.Debug("[RATELIMIT] Inbound raw key is: ", rateLimitKey)

		// This limiter key should be used consistently here out.
		limiterKey := rate.LimiterKey(session, allowanceScope, rateLimitKey, useCustomKey)

		if endpointRLKeySuffix != "" {
			log.Debugf("[RATELIMIT] applying endpoint rate limit key suffix: %s: %s", limiterKey, endpointRLKeySuffix)
			limiterKey = rate.Prefix(limiterKey, endpointRLKeySuffix)
		}

		log.Debug("[RATELIMIT] Rate limiter key is: ", limiterKey)

		limiter := rate.Limiter(l.config, l.limiterStorage)

		switch {
		case limiter != nil:
			err := limiter(r.Context(), limiterKey, apiLimit.Rate, apiLimit.Per)

			if errors.Is(err, rate.ErrLimitExhausted) {
				return sessionFailRateLimit
			}

		case l.config.EnableSentinelRateLimiter:
			if l.limitSentinel(r, session, limiterKey, apiLimit, dryRun) {
				return sessionFailRateLimit
			}
		case l.config.EnableRedisRollingLimiter:
			if l.limitRedis(r, session, limiterKey, apiLimit, dryRun) {
				return sessionFailRateLimit
			}
		default:
			var n float64
			if l.drlManager.Servers != nil {
				n = float64(l.drlManager.Servers.Count())
			}
			cost := apiLimit.Rate / apiLimit.Per
			c := l.config.DRLThreshold
			if c == 0 {
				// defaults to 5
				c = 5
			}

			if n <= 1 || n*c < cost {
				// If we have 1 server, there is no need to strain redis at all the leaky
				// bucket algorithm will suffice.

				bucketKey := limiterKey + ":" + session.LastUpdated
				if useCustomKey {
					bucketKey = limiterKey
				}

				if l.limitDRL(bucketKey, apiLimit, dryRun) {
					return sessionFailRateLimit
				}
			} else {
				if l.limitRedis(r, session, limiterKey, apiLimit, dryRun) {
					return sessionFailRateLimit
				}
			}
		}
	}

	if enableQ {
		if l.config.LegacyEnableAllowanceCountdown {
			session.Allowance = session.Allowance - 1
		}

		if l.RedisQuotaExceeded(r, session, quotaKey, allowanceScope, apiLimit, store, l.config.HashKeys) {
			return sessionFailQuota
		}
	}

	return sessionFailNone

}

Cognitive complexity: 39, Cyclomatic complexity: 23

Uses: errors.Is, rate.ErrLimitExhausted, rate.Limiter, rate.LimiterKey, rate.Prefix.

func (*SessionLimiter) RateLimitInfo

func (l *SessionLimiter) RateLimitInfo(r *http.Request, api *APISpec, endpoints user.Endpoints) (*user.EndpointRateLimitInfo, bool) {
	// Hook per-api settings here (m.Spec...)
	isPrefixMatch := l.config.HttpServerOptions.EnablePathPrefixMatching
	isSuffixMatch := l.config.HttpServerOptions.EnablePathSuffixMatching

	urlPaths := []string{
		api.StripListenPath(r.URL.Path),
		r.URL.Path,
	}

	for _, endpoint := range endpoints {
		if !endpoint.Methods.Contains(r.Method) {
			continue
		}

		pattern := httputil.PreparePathRegexp(endpoint.Path, isPrefixMatch, isSuffixMatch)

		asRegex, err := regexp.Compile(pattern)
		if err != nil {
			log.WithError(err).Error("endpoint rate limit: error compiling regex")
			continue
		}

		for _, urlPath := range urlPaths {
			match := asRegex.MatchString(urlPath)
			if !match {
				break
			}

			for _, endpointMethod := range endpoint.Methods {
				if !strings.EqualFold(endpointMethod.Name, r.Method) {
					continue
				}

				return &user.EndpointRateLimitInfo{
					KeySuffix:	storage.HashStr(fmt.Sprintf("%s:%s", endpointMethod.Name, endpoint.Path)),
					Rate:		endpointMethod.Limit.Rate,
					Per:		endpointMethod.Limit.Per,
				}, true
			}
		}
	}
	return nil, false

}

Cognitive complexity: 19, Cyclomatic complexity: 8

Uses: fmt.Sprintf, httputil.PreparePathRegexp, regexp.Compile, storage.HashStr, strings.EqualFold, user.EndpointRateLimitInfo.

func (*SessionLimiter) RedisQuotaExceeded

RedisQuotaExceeded returns true if the request should be blocked as over quota.

func (l *SessionLimiter) RedisQuotaExceeded(r *http.Request, session *user.SessionState, quotaKey, scope string, limit *user.APILimit, store storage.Handler, hashKeys bool) bool {
	logger := log.WithFields(logrus.Fields{
		"quotaMax":		limit.QuotaMax,
		"quotaRenewalRate":	limit.QuotaRenewalRate,
	})

	if limit.QuotaMax <= 0 {
		return false
	}

	// don't use the requests cancellation context
	ctx := context.Background()

	quotaScope := ""
	if scope != "" {
		quotaScope = scope + "-"
	}

	key := session.KeyID
	if hashKeys {
		key = storage.HashStr(session.KeyID)
	}
	if quotaKey != "" {
		key = quotaKey
	}

	now := time.Now()

	// rawKey is the redis key for quota
	rawKey := QuotaKeyPrefix + quotaScope + key

	var quotaRenewalRate time.Duration
	if limit.QuotaRenewalRate > 0 {
		quotaRenewalRate = time.Second * time.Duration(limit.QuotaRenewalRate)
	}

	conn := l.limiterStorage

	var expired, exists bool
	var expiredAt time.Time

	dur, err := conn.PTTL(ctx, rawKey).Result()
	if err != nil && !errors.Is(err, redis.Nil) {
		logger.WithError(err).Error("error getting key TTL, blocking")
		return true
	}

	// The command returns -2 if the key does not exist.
	// The command returns -1 if the key exists but has no associated expire.
	expired = dur < 0
	exists = dur != -2

	expiredAt = now.Add(dur)

	logger = logger.WithFields(logrus.Fields{
		"exists":	exists,
		"expired":	expired,
		"rawKey":	rawKey,
	})

	increment := func() bool {
		var res *redis.IntCmd
		_, err := conn.Pipelined(ctx, func(pipe redis.Pipeliner) error {
			res = pipe.Incr(ctx, rawKey)
			if res.Val() == 1 && quotaRenewalRate > 0 {
				pipe.Expire(ctx, rawKey, quotaRenewalRate)
			}
			return nil
		})
		if err != nil {
			logger.WithError(err).Error("error incrementing quota key")
			return true
		}

		quota := res.Val()
		blocked := quota-1 >= limit.QuotaMax
		remaining := limit.QuotaMax - quota
		if blocked {
			remaining = 0
		}

		logger = logger.WithField("quota", quota-1)
		logger = logger.WithField("blocked", blocked)
		logger = logger.WithField("remaining", remaining)
		logger.Debug("[QUOTA] Update quota key")

		l.updateSessionQuota(session, scope, remaining, expiredAt.Unix())
		return blocked
	}

	// If exists and not expired, just increment it.
	if exists && !expired {
		return increment()
	}

	// if key is expired and can't renew, update the counter and
	// block traffic going forward.
	if limit.QuotaRenewalRate <= 0 {
		return increment()
	}

	// First, ensure a distributed lock
	locker := limiter.NewLimiter(conn).Locker(rawKey)

	// Lock the key
	if err := locker.Lock(ctx); err != nil {
		// Increment the key if lock fails
		return increment()
	}

	// Unlock the key when done
	defer func() {
		if err := locker.Unlock(ctx); err != nil {
			logger.WithError(err).Error("error unlocking quota key")
		}
	}()

	// locked: reset quota + increment
	conn.Set(ctx, rawKey, 0, quotaRenewalRate)
	return increment()
}

Cognitive complexity: 31, Cyclomatic complexity: 17

Uses: context.Background, errors.Is, limiter.NewLimiter, logrus.Fields, redis.IntCmd, redis.Nil, redis.Pipeliner, storage.HashStr, time.Duration, time.Now, time.Second, time.Time.

func (*StatsDSink) Drain

func (s *StatsDSink) Drain() {
	s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindDrain}
	<-s.drainDoneChan
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*StatsDSink) EmitComplete

func (s *StatsDSink) EmitComplete(job string, status health.CompletionStatus, nanos int64, kvs map[string]string) {
	s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindComplete, Job: job, Status: status, Nanos: nanos}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*StatsDSink) EmitEvent

func (s *StatsDSink) EmitEvent(job, event string, kvs map[string]string) {
	s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindEvent, Job: job, Event: event}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*StatsDSink) EmitEventErr

func (s *StatsDSink) EmitEventErr(job, event string, inputErr error, kvs map[string]string) {
	s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindEventErr, Job: job, Event: event}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*StatsDSink) EmitGauge

func (s *StatsDSink) EmitGauge(job, event string, value float64, kvs map[string]string) {
	s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindGauge, Job: job, Event: event, Value: value}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*StatsDSink) EmitTiming

func (s *StatsDSink) EmitTiming(job, event string, nanos int64, kvs map[string]string) {
	s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindTiming, Job: job, Event: event, Nanos: nanos}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*StatsDSink) Stop

func (s *StatsDSink) Stop() {
	s.cmdChan <- statsdEmitCmd{Kind: statsdCmdKindStop}
	<-s.stopDoneChan
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*StripAuth) EnabledForSpec

func (sa *StripAuth) EnabledForSpec() bool {
	return sa.Spec.StripAuthData
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*StripAuth) Name

func (sa *StripAuth) Name() string {
	return "StripAuth"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*StripAuth) ProcessRequest

func (sa *StripAuth) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {

	strip := func(typ string, config *apidef.AuthConfig) {
		log.WithFields(logrus.Fields{
			"prefix": sa.Name(),
		}).Debugf("%s: %+v\n", typ, config)

		if config.UseParam {
			sa.stripFromParams(r, config)
		}
		sa.stripFromHeaders(r, config)
	}

	for typ, config := range sa.Spec.AuthConfigs {
		strip(typ, &config)
	}

	// For backward compatibility
	if len(sa.Spec.AuthConfigs) == 0 {
		strip(apidef.AuthTokenType, &sa.Spec.Auth)
	}

	return nil, http.StatusOK
}

Cognitive complexity: 10, Cyclomatic complexity: 4

Uses: apidef.AuthConfig, apidef.AuthTokenType, http.StatusOK, logrus.Fields.

func (*SuccessHandler) RecordHit

func (s *SuccessHandler) RecordHit(r *http.Request, timing analytics.Latency, code int, responseCopy *http.Response, cached bool) {

	if s.Spec.DoNotTrack || ctxGetDoNotTrack(r) {
		return
	}

	ip := request.RealIP(r)
	if s.Spec.GlobalConfig.StoreAnalytics(ip) {

		t := time.Now()

		// Track the key ID if it exists
		token := ctxGetAuthToken(r)

		// Track version data
		version := s.Spec.getVersionFromRequest(r)
		if version == "" {
			version = "Non Versioned"
		}

		// If OAuth, we need to grab it from the session, which may or may not exist
		oauthClientID := ""
		var alias string
		session := ctxGetSession(r)
		tags := make([]string, 0, estimateTagsCapacity(session, s.Spec))
		if session != nil {
			oauthClientID = session.OauthClientID
			tags = append(tags, getSessionTags(session)...)
			alias = session.Alias
		}

		if len(s.Spec.TagHeaders) > 0 {
			tags = tagHeaders(r, s.Spec.TagHeaders, tags)
		}

		if len(s.Spec.Tags) > 0 {
			tags = append(tags, s.Spec.Tags...)
		}

		if cached {
			tags = append(tags, "cached-response")
		}

		rawRequest := ""
		rawResponse := ""

		if recordDetail(r, s.Spec) {
			// Get the wire format representation
			var wireFormatReq bytes.Buffer
			r.Write(&wireFormatReq)
			rawRequest = base64.StdEncoding.EncodeToString(wireFormatReq.Bytes())
			// responseCopy, unlike requestCopy, can be nil
			// here - if the response was cached in
			// mw_redis_cache, RecordHit gets passed a nil
			// response copy.
			// TODO: pass a copy of the cached response in
			// mw_redis_cache instead? is there a reason not
			// to include that in the analytics?
			if responseCopy != nil && responseCopy.Body != nil {
				// we need to delete the chunked transfer encoding header to avoid malformed body in our rawResponse
				httputil.RemoveResponseTransferEncoding(responseCopy, "chunked")

				responseContent, err := io.ReadAll(responseCopy.Body)
				if err != nil {
					log.Error("Couldn't read response body", err)
				}

				responseCopy.Body = respBodyReader(r, responseCopy)

				// Get the wire format representation
				var wireFormatRes bytes.Buffer
				responseCopy.Write(&wireFormatRes)
				responseCopy.Body = ioutil.NopCloser(bytes.NewBuffer(responseContent))
				rawResponse = base64.StdEncoding.EncodeToString(wireFormatRes.Bytes())
			}
		}

		trackEP := false
		trackedPath := r.URL.Path
		if p := ctxGetTrackedPath(r); p != "" {
			trackEP = true
			trackedPath = p
		}

		host := r.URL.Host
		if host == "" && s.Spec.target != nil {
			host = s.Spec.target.Host
		}

		record := analytics.AnalyticsRecord{
			Method:		r.Method,
			Host:		host,
			Path:		trackedPath,
			RawPath:	r.URL.Path,
			ContentLength:	r.ContentLength,
			UserAgent:	r.Header.Get(header.UserAgent),
			Day:		t.Day(),
			Month:		t.Month(),
			Year:		t.Year(),
			Hour:		t.Hour(),
			ResponseCode:	code,
			APIKey:		token,
			TimeStamp:	t,
			APIVersion:	version,
			APIName:	s.Spec.Name,
			APIID:		s.Spec.APIID,
			OrgID:		s.Spec.OrgID,
			OauthID:	oauthClientID,
			RequestTime:	timing.Total,
			RawRequest:	rawRequest,
			RawResponse:	rawResponse,
			IPAddress:	ip,
			Geo:		analytics.GeoData{},
			Network:	analytics.NetworkStats{},
			Latency:	timing,
			Tags:		tags,
			Alias:		alias,
			TrackPath:	trackEP,
			ExpireAt:	t,
		}

		if s.Spec.GlobalConfig.AnalyticsConfig.EnableGeoIP {
			record.GetGeo(ip, s.Gw.Analytics.GeoIPDB)
		}

		recordGraphDetails(&record, r, responseCopy, s.Spec)
		// skip tagging subgraph requests for graphpump, it only handles generated supergraph requests
		if s.Spec.GraphQL.Enabled && s.Spec.GraphQL.ExecutionMode != apidef.GraphQLExecutionModeSubgraph {
			record.Tags = append(record.Tags, "tyk-graph-analytics")
			record.ApiSchema = base64.StdEncoding.EncodeToString([]byte(s.Spec.GraphQL.Schema))
		}

		expiresAfter := s.Spec.ExpireAnalyticsAfter

		if s.Spec.GlobalConfig.EnforceOrgDataAge {
			orgExpireDataTime := s.OrgSessionExpiry(s.Spec.OrgID)

			if orgExpireDataTime > 0 {
				expiresAfter = orgExpireDataTime
			}
		}

		record.SetExpiry(expiresAfter)

		if s.Spec.GlobalConfig.AnalyticsConfig.NormaliseUrls.Enabled {
			NormalisePath(&record, &s.Spec.GlobalConfig)
		}

		if s.Spec.AnalyticsPlugin.Enabled {

			//send to plugin
			_ = s.Spec.AnalyticsPluginConfig.processRecord(&record)

		}

		err := s.Gw.Analytics.RecordHit(&record)
		if err != nil {
			log.WithError(err).Error("could not store analytic record")
		}
	}

	// Report in health check
	reportHealthValue(s.Spec, RequestLog, strconv.FormatInt(timing.Total, 10))
}

Cognitive complexity: 41, Cyclomatic complexity: 24

Uses: analytics.AnalyticsRecord, analytics.GeoData, analytics.NetworkStats, apidef.GraphQLExecutionModeSubgraph, base64.StdEncoding, bytes.Buffer, bytes.NewBuffer, header.UserAgent, httputil.RemoveResponseTransferEncoding, io.ReadAll, ioutil.NopCloser, request.RealIP, strconv.FormatInt, time.Now.

func (*SuccessHandler) ServeHTTP

ServeHTTP will store the request details in the analytics store if necessary and proxy the request to it's final destination, this is invoked by the ProxyHandler or right at the start of a request chain if the URL Spec states the path is Ignored

func (s *SuccessHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) *http.Response {
	log.Debug("Started proxy")
	defer s.Base().UpdateRequestSession(r)

	// Make sure we get the correct target URL
	s.Spec.SanitizeProxyPaths(r)

	addVersionHeader(w, r, s.Spec.GlobalConfig)

	t1 := time.Now()
	resp := s.Proxy.ServeHTTP(w, r)

	millisec := DurationToMillisecond(time.Since(t1))
	log.Debug("Upstream request took (ms): ", millisec)

	if resp.Response != nil {
		latency := analytics.Latency{
			Total:		int64(millisec),
			Upstream:	int64(DurationToMillisecond(resp.UpstreamLatency)),
		}
		s.RecordHit(r, latency, resp.Response.StatusCode, resp.Response, false)
		s.RecordAccessLog(r, resp.Response, latency)
	}
	log.Debug("Done proxy")

	return nil
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: analytics.Latency, time.Now, time.Since.

func (*SuccessHandler) ServeHTTPWithCache

ServeHTTPWithCache will store the request details in the analytics store if necessary and proxy the request to it's final destination, this is invoked by the ProxyHandler or right at the start of a request chain if the URL Spec states the path is Ignored Itwill also return a response object for the cache

func (s *SuccessHandler) ServeHTTPWithCache(w http.ResponseWriter, r *http.Request) ProxyResponse {

	// Make sure we get the correct target URL
	s.Spec.SanitizeProxyPaths(r)

	t1 := time.Now()
	inRes := s.Proxy.ServeHTTPForCache(w, r)
	millisec := DurationToMillisecond(time.Since(t1))

	addVersionHeader(w, r, s.Spec.GlobalConfig)

	log.Debug("Upstream request took (ms): ", millisec)

	if inRes.Response != nil {
		latency := analytics.Latency{
			Total:		int64(millisec),
			Upstream:	int64(DurationToMillisecond(inRes.UpstreamLatency)),
		}
		s.RecordHit(r, latency, inRes.Response.StatusCode, inRes.Response, false)
	}

	return inRes
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: analytics.Latency, time.Now, time.Since.

func (*Test) AddDynamicHandler

func (s *Test) AddDynamicHandler(path string, handlerFunc http.HandlerFunc) {
	path = strings.Trim(path, "/")
	s.dynamicHandlers[path] = handlerFunc
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: strings.Trim.

func (*Test) BundleHandleFunc

func (s *Test) BundleHandleFunc(w http.ResponseWriter, r *http.Request) {
	s.Gw.TestBundleMu.Lock()
	defer s.Gw.TestBundleMu.Unlock()

	bundleName := strings.Replace(r.URL.Path, "/bundles/", "", -1)
	bundle, exists := s.Gw.TestBundles[bundleName]
	if !exists {
		log.Warning(s.Gw.TestBundles)
		http.Error(w, "Bundle not found", http.StatusNotFound)
		return
	}

	w.Header().Set("Content-Type", "application/zip")

	z := zip.NewWriter(w)
	for name, content := range bundle {
		f, _ := z.Create(name)
		f.Write([]byte(content))
	}
	z.Close()
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: http.Error, http.StatusNotFound, strings.Replace, zip.NewWriter.

func (*Test) Close

func (s *Test) Close() {
	defer s.cancel()

	for _, p := range s.Gw.DefaultProxyMux.proxies {
		if p.listener != nil {
			p.listener.Close()
		}
	}

	gwConfig := s.Gw.GetConfig()

	s.Gw.DefaultProxyMux.swap(&proxyMux{}, s.Gw)
	if s.config.SeparateControlAPI {
		gwConfig.ControlAPIPort = 0
		s.Gw.SetConfig(gwConfig)
	}

	// if jsvm enabled we need to unmount to prevent high memory consumption
	if s.Gw.GetConfig().EnableJSVM {
		s.Gw.GlobalEventsJSVM.VM = nil
	}

	ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	err := s.HttpHandler.Shutdown(ctxShutDown)
	if err != nil {
		log.WithError(err).Error("shutting down the http handler")
	} else {
		log.Info("server exited properly")
	}

	s.Gw.Analytics.Stop()
	s.Gw.ReloadTestCase.StopTicker()
	s.Gw.GlobalHostChecker.StopPoller()
	s.Gw.NewRelicApplication.Shutdown(5 * time.Second)

	err = s.RemoveApis()
	if err != nil {
		log.Error("could not remove apis")
	}

	s.Gw.cacheClose()
}

Cognitive complexity: 16, Cyclomatic complexity: 7

Uses: context.Background, context.WithTimeout, time.Second.

func (*Test) CreatePolicy

func (s *Test) CreatePolicy(pGen ...func(p *user.Policy)) string {

	pID := s.Gw.keyGen.GenerateAuthKey("")
	pol := CreateStandardPolicy()
	pol.ID = pID

	if len(pGen) > 0 {
		pGen[0](pol)
	}

	s.Gw.policiesMu.Lock()
	s.Gw.policiesByID[pol.ID] = *pol
	s.Gw.policiesMu.Unlock()

	return pol.ID
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*Test) CreateSession

func (s *Test) CreateSession(sGen ...func(s *user.SessionState)) (*user.SessionState, string) {
	session := CreateStandardSession()
	if len(sGen) > 0 {
		sGen[0](session)
	}

	client := GetTLSClient(nil, nil)

	resp, err := s.Do(test.TestCase{
		Method:		http.MethodPost,
		Path:		"/tyk/keys/create",
		Data:		session,
		Client:		client,
		AdminAuth:	true,
	})

	if err != nil {
		log.Fatal("Error while creating session:", err)
		return nil, ""
	}

	keySuccess := apiModifyKeySuccess{}
	err = json.NewDecoder(resp.Body).Decode(&keySuccess)
	if err != nil {
		log.Fatal("Error while decoding session response:", err)
		return nil, ""
	}

	createdSession, _ := s.Gw.GlobalSessionManager.SessionDetail(session.OrgID, keySuccess.Key, false)

	return &createdSession, keySuccess.Key
}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: http.MethodPost, json.NewDecoder, test.TestCase.

func (*Test) DeletePolicy

func (s *Test) DeletePolicy(policyID string) {
	s.Gw.policiesMu.Lock()
	delete(s.Gw.policiesByID, policyID)
	s.Gw.policiesMu.Unlock()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Test) Do

func (s *Test) Do(tc test.TestCase) (*http.Response, error) {
	req, _ := s.testRunner.RequestBuilder(&tc)
	return s.testRunner.Do(req, &tc)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Test) EnablePort

func (s *Test) EnablePort(port int, protocol string) {
	c := s.Gw.GetConfig()
	if c.PortWhiteList == nil {
		c.PortWhiteList = map[string]config.PortWhiteList{
			protocol: {
				Ports: []int{port},
			},
		}
	} else {
		m, ok := c.PortWhiteList[protocol]
		if !ok {
			m = config.PortWhiteList{
				Ports: []int{port},
			}
		} else {
			m.Ports = append(m.Ports, port)
		}
		c.PortWhiteList[protocol] = m
	}
	s.Gw.SetConfig(c)
}

Cognitive complexity: 13, Cyclomatic complexity: 3

Uses: config.PortWhiteList.

func (*Test) GetApiById

func (s *Test) GetApiById(apiId string) *APISpec {
	return s.Gw.getApiSpec(apiId)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Test) GetPolicyById

func (s *Test) GetPolicyById(policyId string) (user.Policy, bool) {
	s.Gw.policiesMu.Lock()
	defer s.Gw.policiesMu.Unlock()
	pol, found := s.Gw.policiesByID[policyId]
	return pol, found
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Test) RegisterBundle

func (s *Test) RegisterBundle(name string, files map[string]string) string {
	s.Gw.TestBundleMu.Lock()
	defer s.Gw.TestBundleMu.Unlock()

	bundleID := name + "-" + uuid.NewHex() + ".zip"
	s.Gw.TestBundles[bundleID] = files

	return bundleID
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: uuid.NewHex.

func (*Test) RegisterJSFileMiddleware

func (s *Test) RegisterJSFileMiddleware(apiid string, files map[string]string) {
	gwConfig := s.Gw.GetConfig()
	err := os.MkdirAll(gwConfig.MiddlewarePath+"/"+apiid+"/post", 0755)
	if err != nil {
		log.WithError(err).Error("creating directory in middleware post path")
	}
	err = os.MkdirAll(gwConfig.MiddlewarePath+"/"+apiid+"/pre", 0755)
	if err != nil {
		log.WithError(err).Error("creating directory in middleware pre path")
	}

	for file, content := range files {
		err = ioutil.WriteFile(gwConfig.MiddlewarePath+"/"+apiid+"/"+file, []byte(content), 0755)
		if err != nil {
			log.WithError(err).Error("writing in file")
		}
	}
}

Cognitive complexity: 9, Cyclomatic complexity: 5

Uses: ioutil.WriteFile, os.MkdirAll.

func (*Test) ReloadGatewayProxy

func (s *Test) ReloadGatewayProxy() {
	s.Gw.DefaultProxyMux.swap(&proxyMux{}, s.Gw)
	s.Gw.startServer()
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*Test) RemoveApis

RemoveApis clean all the apis from a living gw

func (s *Test) RemoveApis() error {
	s.Gw.apisMu.Lock()
	defer func() {
		s.Gw.apiSpecs = []*APISpec{}
		s.Gw.apisByID = map[string]*APISpec{}
		s.Gw.apisMu.Unlock()
	}()

	// clear bundle caches
	for _, spec := range s.Gw.apiSpecs {
		destPath := s.Gw.getBundleDestPath(spec)
		if _, err := os.Stat(destPath); err == nil {
			err = os.RemoveAll(destPath)
			log.WithError(err).Infof("Clearing bundle cache: %s", destPath)
		}
	}

	err := os.RemoveAll(s.Gw.GetConfig().AppPath)

	if err != nil {
		log.WithError(err).Error("removing apis from gw")
	}

	return err
}

Cognitive complexity: 10, Cyclomatic complexity: 4

Uses: os.RemoveAll, os.Stat.

func (*Test) ResetTestConfig

Deprecated: ResetTestConfig resets the config for the global gateway.

The function does nothing, the correct way is to reuse StartTest(), filling the config from the provided callback. Usage impacts a few tests (small). See TestCustomDomain for an updated test.

func (s *Test) ResetTestConfig() {
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Test) Run

func (s *Test) Run(t testing.TB, testCases ...test.TestCase) (*http.Response, error) {
	t.Helper()
	return s.testRunner.Run(t, testCases...)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Test) RunExt

TODO:(gernest) when hot reload is supported enable this.

func (s *Test) RunExt(t testing.TB, testCases ...test.TestCase) {
	t.Helper()

	s.Run(t, testCases...)
	var testMatrix = []struct {
		goagain			bool
		overrideDefaults	bool
	}{
		{false, false},
		{false, true},
		{true, true},
		{true, false},
	}

	for _, m := range testMatrix {
		s.config.HotReload = m.goagain
		s.config.overrideDefaults = m.overrideDefaults

		title := fmt.Sprintf("hotReload: %v, overrideDefaults: %v", m.goagain, m.overrideDefaults)
		t.(*testing.T).Run(title, func(t *testing.T) {
			s.Run(t, testCases...)
		})
	}
}

Cognitive complexity: 10, Cyclomatic complexity: 2

Uses: fmt.Sprintf, testing.T.

func (*Test) StopRPCClient

func (s *Test) StopRPCClient() {
	rpc.Reset()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: rpc.Reset.

func (*TrackEndpointMiddleware) EnabledForSpec

func (t *TrackEndpointMiddleware) EnabledForSpec() bool {
	if !t.Spec.GlobalConfig.EnableAnalytics || t.Spec.DoNotTrack {
		return false
	}

	for _, version := range t.Spec.VersionData.Versions {
		if len(version.ExtendedPaths.TrackEndpoints) > 0 || len(version.ExtendedPaths.DoNotTrackEndpoints) > 0 {
			return true
		}
	}

	return false
}

Cognitive complexity: 7, Cyclomatic complexity: 6

func (*TrackEndpointMiddleware) Name

func (t *TrackEndpointMiddleware) Name() string {
	return "TrackEndpointMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*TrackEndpointMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (t *TrackEndpointMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	vInfo, _ := t.Spec.Version(r)
	versionPaths := t.Spec.RxPaths[vInfo.Name]
	foundTracked, metaTrack := t.Spec.CheckSpecMatchesStatus(r, versionPaths, RequestTracked)
	if foundTracked {
		ctxSetTrackedPath(r, metaTrack.(*apidef.TrackEndpointMeta).Path)
	}

	foundDnTrack, _ := t.Spec.CheckSpecMatchesStatus(r, versionPaths, RequestNotTracked)
	if foundDnTrack {
		ctxSetDoNotTrack(r, true)
	}

	return nil, http.StatusOK
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: apidef.TrackEndpointMeta, http.StatusOK.

func (*TransformHeaders) EnabledForSpec

func (t *TransformHeaders) EnabledForSpec() bool {
	for _, version := range t.Spec.VersionData.Versions {
		if version.GlobalHeadersEnabled() {
			return true
		}

		if version.HasEndpointReqHeader() {
			return true
		}
	}
	return false
}

Cognitive complexity: 7, Cyclomatic complexity: 4

func (*TransformHeaders) Name

func (t *TransformHeaders) Name() string {
	return "TransformHeaders"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*TransformHeaders) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (t *TransformHeaders) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	vInfo, _ := t.Spec.Version(r)

	ignoreCanonical := t.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey

	// Manage global headers first - remove
	if !vInfo.GlobalHeadersDisabled {
		for _, gdKey := range vInfo.GlobalHeadersRemove {
			t.Logger().Debug("Removing: ", gdKey)
			r.Header.Del(gdKey)
		}

		// Add
		for nKey, nVal := range vInfo.GlobalHeaders {
			t.Logger().Debug("Adding: ", nKey)
			setCustomHeader(r.Header, nKey, t.Gw.ReplaceTykVariables(r, nVal, false), ignoreCanonical)
		}
	}

	versionPaths := t.Spec.RxPaths[vInfo.Name]
	found, meta := t.Spec.CheckSpecMatchesStatus(r, versionPaths, HeaderInjected)
	if found {
		hmeta := meta.(*apidef.HeaderInjectionMeta)
		for _, dKey := range hmeta.DeleteHeaders {
			r.Header.Del(dKey)
		}
		for nKey, nVal := range hmeta.AddHeaders {
			setCustomHeader(r.Header, nKey, t.Gw.ReplaceTykVariables(r, nVal, false), ignoreCanonical)
		}
	}

	return nil, http.StatusOK
}

Cognitive complexity: 17, Cyclomatic complexity: 7

Uses: apidef.HeaderInjectionMeta, http.StatusOK.

func (*TransformJQMiddleware) EnabledForSpec

func (t *TransformJQMiddleware) EnabledForSpec() bool {
	for _, version := range t.Spec.VersionData.Versions {
		if len(version.ExtendedPaths.TransformJQ) > 0 {
			log.Warning("JQ transform not supported.")
			return false
		}
	}

	return false
}

Cognitive complexity: 5, Cyclomatic complexity: 3

func (*TransformJQMiddleware) Name

func (t *TransformJQMiddleware) Name() string {
	return "TransformJQMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*TransformJQMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (t *TransformJQMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	return nil, 200
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*TransformMethod) EnabledForSpec

func (t *TransformMethod) EnabledForSpec() bool {
	for _, version := range t.Spec.VersionData.Versions {
		if len(version.ExtendedPaths.MethodTransforms) > 0 {
			return true
		}
	}
	return false
}

Cognitive complexity: 5, Cyclomatic complexity: 3

func (*TransformMethod) Name

func (t *TransformMethod) Name() string {
	return "TransformMethod"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*TransformMethod) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (t *TransformMethod) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	version, _ := t.Spec.Version(r)
	versionPaths := t.Spec.RxPaths[version.Name]
	found, meta := t.Spec.CheckSpecMatchesStatus(r, versionPaths, MethodTransformed)
	if !found {
		return nil, http.StatusOK
	}
	mmeta := meta.(*apidef.MethodTransformMeta)
	toMethod := strings.ToUpper(mmeta.ToMethod)

	ctxSetRequestMethod(r, r.Method)

	switch strings.ToUpper(mmeta.ToMethod) {
	case "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH":
		ctxSetTransformRequestMethod(r, toMethod)
	default:
		return errors.New("Method not allowed"), http.StatusMethodNotAllowed
	}
	return nil, http.StatusOK
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: apidef.MethodTransformMeta, errors.New, http.StatusMethodNotAllowed, http.StatusOK, strings.ToUpper.

func (*TransformMiddleware) EnabledForSpec

func (t *TransformMiddleware) EnabledForSpec() bool {
	for _, version := range t.Spec.VersionData.Versions {
		if len(version.ExtendedPaths.Transform) > 0 {
			return true
		}
	}
	return false
}

Cognitive complexity: 5, Cyclomatic complexity: 3

func (*TransformMiddleware) Name

func (t *TransformMiddleware) Name() string {
	return "TransformMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*TransformMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (t *TransformMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	vInfo, _ := t.Spec.Version(r)
	versionPaths := t.Spec.RxPaths[vInfo.Name]
	found, meta := t.Spec.CheckSpecMatchesStatus(r, versionPaths, Transformed)
	if !found {
		return nil, http.StatusOK
	}
	err := transformBody(r, meta.(*TransformSpec), t)
	if err != nil {
		t.Logger().WithError(err).Error("Body transform failure")
	}
	return nil, http.StatusOK
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: http.StatusOK.

func (*TykRoundTripper) RoundTrip

func (rt *TykRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {

	hasInternalHeader := r.Header.Get(apidef.TykInternalApiHeader) != ""

	if r.URL.Scheme == "tyk" || hasInternalHeader {
		if hasInternalHeader {
			r.Header.Del(apidef.TykInternalApiHeader)
		}

		handler, _, found := rt.Gw.findInternalHttpHandlerByNameOrID(r.Host)
		if !found {
			rt.logger.WithField("looping_url", "tyk://"+r.Host).Error("Couldn't detect target")
			return nil, errors.New("handler could")
		}

		rt.logger.WithField("looping_url", "tyk://"+r.Host).Debug("Executing request on internal route")

		return handleInMemoryLoop(handler, r)
	}

	if rt.Gw.GetConfig().OpenTelemetry.Enabled {
		var baseRoundTripper http.RoundTripper = rt.transport
		if rt.h2ctransport != nil {
			baseRoundTripper = rt.h2ctransport
		}

		tr := otel.HTTPRoundTripper(baseRoundTripper)
		return tr.RoundTrip(r)
	}
	if rt.h2ctransport != nil {
		return rt.h2ctransport.RoundTrip(r)
	}

	return rt.transport.RoundTrip(r)
}

Cognitive complexity: 12, Cyclomatic complexity: 8

Uses: apidef.TykInternalApiHeader, errors.New, http.RoundTripper, otel.HTTPRoundTripper.

func (*URLRewriteMiddleware) CheckHostRewrite

func (m *URLRewriteMiddleware) CheckHostRewrite(oldPath, newTarget string, r *http.Request) error {
	oldAsURL, errParseOld := url.Parse(oldPath)
	if errParseOld != nil {
		return errParseOld
	}

	newAsURL, errParseNew := url.Parse(newTarget)
	if errParseNew != nil {
		return errParseNew
	}

	if shouldRewriteHost(oldAsURL, newAsURL) {
		log.Debug("Detected a host rewrite in pattern!")
		setCtxValue(r, ctx.RetainHost, true)
	}

	return nil
}

Cognitive complexity: 6, Cyclomatic complexity: 4

Uses: ctx.RetainHost, url.Parse.

func (*URLRewriteMiddleware) EnabledForSpec

func (m *URLRewriteMiddleware) EnabledForSpec() bool {
	if m.InitTriggerRx() {
		m.Spec.URLRewriteEnabled = true
		return true
	}
	return false
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*URLRewriteMiddleware) InitTriggerRx

InitTriggerRx will go over all defined URLRewrite triggers and initialize them. It will skip disabled triggers, returning true if at least one trigger is enabled.

func (m *URLRewriteMiddleware) InitTriggerRx() (enabled bool) {
	// Generate regexp for each special match parameter
	for verKey := range m.Spec.VersionData.Versions {
		for pathKey := range m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite {
			rewrite := m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite[pathKey]

			if rewrite.Disabled {
				continue
			}

			enabled = true

			for trKey := range rewrite.Triggers {
				tr := rewrite.Triggers[trKey]

				for key, h := range tr.Options.HeaderMatches {
					h.Init()
					tr.Options.HeaderMatches[key] = h
				}
				for key, q := range tr.Options.QueryValMatches {
					q.Init()
					tr.Options.QueryValMatches[key] = q
				}
				for key, h := range tr.Options.SessionMetaMatches {
					h.Init()
					tr.Options.SessionMetaMatches[key] = h
				}
				for key, h := range tr.Options.RequestContextMatches {
					h.Init()
					tr.Options.RequestContextMatches[key] = h
				}
				for key, h := range tr.Options.PathPartMatches {
					h.Init()
					tr.Options.PathPartMatches[key] = h
				}
				if tr.Options.PayloadMatches.MatchPattern != "" {
					tr.Options.PayloadMatches.Init()
				}

				rewrite.Triggers[trKey] = tr
			}

			m.Spec.VersionData.Versions[verKey].ExtendedPaths.URLRewrite[pathKey] = rewrite
		}
	}

	return
}

Cognitive complexity: 28, Cyclomatic complexity: 11

func (*URLRewriteMiddleware) Name

func (m *URLRewriteMiddleware) Name() string {
	return "URLRewriteMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*URLRewriteMiddleware) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (m *URLRewriteMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	vInfo, _ := m.Spec.Version(r)
	found, meta := m.Spec.CheckSpecMatchesStatus(r, m.Spec.RxPaths[vInfo.Name], URLRewrite)

	if !found {
		return nil, http.StatusOK
	}

	//Used for looping feature
	//To get host and query parameters
	ctxSetOrigRequestURL(r, r.URL)

	log.Debug("Rewriter active")
	umeta := meta.(*apidef.URLRewriteMeta)
	log.Debug(r.URL)
	oldPath := r.URL.String()

	p, err := m.Gw.urlRewrite(umeta, r)
	if err != nil {
		log.Error(err)
		return err, http.StatusInternalServerError
	}

	// During looping target can be API name
	// Need make it compatible with URL parser
	if strings.HasPrefix(p, LoopScheme) {
		p = LoopHostRE.ReplaceAllStringFunc(p, func(match string) string {
			host := strings.TrimPrefix(match, LoopScheme+"://")
			return LoopingUrl(host)
		})
	}

	if err = m.CheckHostRewrite(oldPath, p, r); err != nil {
		log.WithError(err).WithField("from", oldPath).WithField("to", p).Error("Checking Host rewrite: error parsing URL")
	}

	newURL, err := url.Parse(p)
	if err != nil {
		log.Error("URL Rewrite failed, could not parse: ", p)
	} else {
		//Setting new path here breaks request middleware
		//New path is set in DummyProxyHandler/Cache middleware
		ctxSetURLRewriteTarget(r, newURL)
	}
	return nil, http.StatusOK
}

Cognitive complexity: 10, Cyclomatic complexity: 4

Uses: apidef.URLRewriteMeta, http.StatusInternalServerError, http.StatusOK, strings.HasPrefix, strings.TrimPrefix, url.Parse.

func (*UptimeReportData) SetExpiry

func (u *UptimeReportData) SetExpiry(expiresInSeconds int64) {
	expiry := time.Duration(expiresInSeconds) * time.Second

	if expiresInSeconds == 0 {
		// Expiry is set to 100 years
		expiry = (24 * time.Hour) * (365 * 100)
	}

	t := time.Now()
	t2 := t.Add(expiry)
	u.ExpireAt = t2
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: time.Duration, time.Hour, time.Now, time.Second.

func (*ValidateJSON) EnabledForSpec

func (k *ValidateJSON) EnabledForSpec() bool {
	for _, v := range k.Spec.VersionData.Versions {
		if len(v.ExtendedPaths.ValidateJSON) > 0 {
			return true
		}
	}

	return false
}

Cognitive complexity: 5, Cyclomatic complexity: 3

func (*ValidateJSON) Name

func (k *ValidateJSON) Name() string {
	return "ValidateJSON"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ValidateJSON) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (k *ValidateJSON) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	versionInfo, _ := k.Spec.Version(r)
	versionPaths := k.Spec.RxPaths[versionInfo.Name]
	found, meta := k.Spec.CheckSpecMatchesStatus(r, versionPaths, ValidateJSONRequest)
	if !found {
		return nil, http.StatusOK
	}

	vPathMeta := meta.(*apidef.ValidatePathMeta)
	if vPathMeta.Schema == nil {
		return errors.New("no schemas to validate against"), http.StatusInternalServerError
	}

	nopCloseRequestBody(r)
	// Load input body into gojsonschema
	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		return err, http.StatusBadRequest
	}
	r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
	defer r.Body.Close()
	inputLoader := gojsonschema.NewBytesLoader(bodyBytes)

	// Perform validation
	result, err := gojsonschema.Validate(vPathMeta.SchemaCache, inputLoader)
	if err != nil {
		return fmt.Errorf("JSON parsing error: %w", err), http.StatusBadRequest
	}

	// Handle Failure
	if !result.Valid() {
		if vPathMeta.ErrorResponseCode == 0 {
			vPathMeta.ErrorResponseCode = http.StatusUnprocessableEntity
		}

		return k.formatError(result.Errors()), vPathMeta.ErrorResponseCode
	}

	// Handle Success
	return nil, http.StatusOK
}

Cognitive complexity: 13, Cyclomatic complexity: 7

Uses: apidef.ValidatePathMeta, bytes.NewBuffer, errors.New, fmt.Errorf, gojsonschema.NewBytesLoader, gojsonschema.Validate, http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, http.StatusUnprocessableEntity, io.NopCloser, io.ReadAll.

func (*ValidateRequest) EnabledForSpec

func (k *ValidateRequest) EnabledForSpec() bool {
	if !k.Spec.IsOAS {
		return false
	}

	middleware := k.Spec.OAS.GetTykExtension().Middleware
	if middleware == nil {
		return false
	}

	if len(middleware.Operations) == 0 {
		return false
	}

	for _, operation := range middleware.Operations {
		if operation.ValidateRequest == nil {
			continue
		}

		if operation.ValidateRequest.Enabled {
			k.Spec.HasValidateRequest = true
			return true
		}
	}

	return false
}

Cognitive complexity: 13, Cyclomatic complexity: 7

func (*ValidateRequest) Name

func (k *ValidateRequest) Name() string {
	return "ValidateRequest"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*ValidateRequest) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (k *ValidateRequest) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	operation := ctxGetOperation(r)
	if operation == nil {
		return nil, http.StatusOK
	}

	validateRequest := operation.ValidateRequest
	if validateRequest == nil || !validateRequest.Enabled {
		return nil, http.StatusOK
	}

	errResponseCode := http.StatusUnprocessableEntity
	if validateRequest.ErrorResponseCode != 0 {
		errResponseCode = validateRequest.ErrorResponseCode
	}

	// Validate request
	requestValidationInput := &openapi3filter.RequestValidationInput{
		Request:	r,
		PathParams:	operation.pathParams,
		Route:		operation.route,
		Options: &openapi3filter.Options{
			AuthenticationFunc: func(ctx context.Context, input *openapi3filter.AuthenticationInput) error {
				return nil
			},
		},
	}

	err := openapi3filter.ValidateRequest(r.Context(), requestValidationInput)
	if err != nil {
		return fmt.Errorf("request validation error: %w", err), errResponseCode
	}

	// Handle Success
	return nil, http.StatusOK
}

Cognitive complexity: 12, Cyclomatic complexity: 6

Uses: context.Context, fmt.Errorf, http.StatusOK, http.StatusUnprocessableEntity, openapi3filter.AuthenticationInput, openapi3filter.Options, openapi3filter.RequestValidationInput, openapi3filter.ValidateRequest.

func (*ValueExtractor) Extract

func (e *ValueExtractor) Extract(input interface{}) string {
	headerValue := input.(string)
	return headerValue
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*ValueExtractor) ExtractAndCheck

func (e *ValueExtractor) ExtractAndCheck(r *http.Request) (sessionID string, returnOverrides ReturnOverrides) {
	var extractorOutput string
	var err error
	switch e.Config.ExtractFrom {
	case apidef.HeaderSource:
		extractorOutput, err = e.ExtractHeader(r)
	case apidef.FormSource:
		extractorOutput, err = e.ExtractForm(r, e.IDExtractorConfig.FormParamName)
	}

	if err != nil {
		returnOverrides = e.Error(r, err, "ValueExtractor error")
		return sessionID, returnOverrides
	}

	sessionID = e.GenerateSessionID(extractorOutput, e.BaseMiddleware)
	previousSession, keyExists := e.CheckSessionAndIdentityForValidKey(sessionID, r)
	sessionID = previousSession.KeyID

	if keyExists {
		if previousSession.IdExtractorDeadline > time.Now().Unix() {
			ctxSetSession(r, &previousSession, true, e.Gw.GetConfig().HashKeys)
			returnOverrides = ReturnOverrides{
				ResponseCode: 200,
			}
		}
	}

	return sessionID, returnOverrides
}

Cognitive complexity: 11, Cyclomatic complexity: 7

Uses: apidef.FormSource, apidef.HeaderSource, time.Now.

func (*VersionCheck) DoMockReply

func (v *VersionCheck) DoMockReply(w http.ResponseWriter, meta apidef.MockResponseMeta) {
	responseMessage := []byte(meta.Body)
	for header, value := range meta.Headers {
		w.Header().Add(header, value)
	}

	w.WriteHeader(meta.Code)
	w.Write(responseMessage)
}

Cognitive complexity: 3, Cyclomatic complexity: 2

func (*VersionCheck) Init

func (v *VersionCheck) Init() {
	v.sh = SuccessHandler{v.BaseMiddleware}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*VersionCheck) Name

func (v *VersionCheck) Name() string {
	return "VersionCheck"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*VersionCheck) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (v *VersionCheck) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	targetVersion := v.Spec.getVersionFromRequest(r)
	if targetVersion == "" {
		targetVersion = v.Spec.VersionDefinition.Default
	}

	ctxSetSpanAttributes(r, v.Name(), otel.APIVersionAttribute(targetVersion))

	isBase := func(vName string) bool {
		return vName == apidef.Self || vName == v.Spec.VersionDefinition.Name
	}

	if v.Spec.VersionDefinition.Enabled && !isBase(targetVersion) {
		if targetVersion == "" {
			return errors.New(string(VersionNotFound)), http.StatusForbidden
		}

		subVersionID := v.Spec.VersionDefinition.Versions[targetVersion]
		handler, _, found := v.Gw.findInternalHttpHandlerByNameOrID(subVersionID)
		if !found {
			if !v.Spec.VersionDefinition.FallbackToDefault {
				return errors.New(string(VersionDoesNotExist)), http.StatusNotFound
			}

			if isBase(v.Spec.VersionDefinition.Default) {
				goto outside
			}

			targetID, ok := v.Spec.VersionDefinition.Versions[v.Spec.VersionDefinition.Default]
			if !ok {
				log.Errorf("fallback to default but %s is not in the versions list", v.Spec.VersionDefinition.Default)
				return errors.New(http.StatusText(http.StatusInternalServerError)), http.StatusInternalServerError
			}

			handler, _, found = v.Gw.findInternalHttpHandlerByNameOrID(targetID)
			if !found {
				log.Errorf("fallback to default but there is no such API found with the id: %s", targetID)
				return errors.New(http.StatusText(http.StatusInternalServerError)), http.StatusInternalServerError
			}
		}

		v.Spec.SanitizeProxyPaths(r)

		handler.ServeHTTP(w, r)
		return nil, mwStatusRespond
	}
outside:

	// For OAS route matching
	if v.Spec.HasMock || v.Spec.HasValidateRequest {
		findRouteAndOperation(v.Spec, r)
	}

	// Check versioning, blacklist, whitelist and ignored status
	requestValid, stat := v.Spec.RequestValid(r)
	if !requestValid {
		// Fire a versioning failure event
		v.FireEvent(EventVersionFailure, EventVersionFailureMeta{
			EventMetaDefault: EventMetaDefault{
				Message:		"Attempted access to disallowed version / path.",
				OriginatingRequest:	EncodeRequestToEvent(r),
			},
			Path:	r.URL.Path,
			Origin:	request.RealIP(r),
			Reason:	string(stat),
		})
		return errors.New(string(stat)), http.StatusForbidden
	}

	versionInfo, _ := v.Spec.Version(r)
	versionPaths := v.Spec.RxPaths[versionInfo.Name]
	whiteListStatus := v.Spec.WhiteListEnabled[versionInfo.Name]

	// We handle redirects before ignores in case we aren't using a whitelist
	if stat == StatusRedirectFlowByReply {
		_, meta := v.Spec.URLAllowedAndIgnored(r, versionPaths, whiteListStatus)
		var mockMeta apidef.MockResponseMeta
		var ok bool
		if mockMeta, ok = meta.(apidef.MockResponseMeta); !ok {
			endpointMethodMeta := meta.(*apidef.EndpointMethodMeta)
			mockMeta.Body = endpointMethodMeta.Data
			mockMeta.Headers = endpointMethodMeta.Headers
			mockMeta.Code = endpointMethodMeta.Code
		}

		v.DoMockReply(w, mockMeta)
		return nil, mwStatusRespond
	}

	if !v.Spec.ExpirationTs.IsZero() {
		w.Header().Set(XTykAPIExpires, v.Spec.ExpirationTs.Format(time.RFC1123))
	} else if expTime := versionInfo.ExpiryTime(); !expTime.IsZero() {	// Deprecated
		w.Header().Set(XTykAPIExpires, expTime.Format(time.RFC1123))
	}

	if stat == StatusOkAndIgnore {
		ctxSetRequestStatus(r, stat)
	}

	return nil, http.StatusOK
}

Cognitive complexity: 34, Cyclomatic complexity: 19

Uses: apidef.EndpointMethodMeta, apidef.MockResponseMeta, apidef.Self, errors.New, http.StatusForbidden, http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, http.StatusText, otel.APIVersionAttribute, request.RealIP, time.RFC1123.

func (*VersionsHandler) ServeHTTP

func (h *VersionsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	apiID := mux.Vars(r)["apiID"]
	searchText := strings.ToLower(r.URL.Query().Get("searchText"))
	justInternal := r.URL.Query().Get("accessType") == "internal"
	justExternal := r.URL.Query().Get("accessType") == "external"

	canInclude := func(api *apidef.APIDefinition, name string) bool {
		if justInternal && !api.Internal {
			return false
		}

		if justExternal && api.Internal {
			return false
		}

		if searchText == "" {
			return true
		}

		return strings.Contains(strings.ToLower(name), searchText)
	}

	baseAPI, err := h.getApiDef(apiID)
	if err != nil {
		doJSONWrite(w, http.StatusNotFound, apiError(err.Error()))
		return
	}

	var versionMetas VersionMetas

	for name, id := range baseAPI.VersionDefinition.Versions {
		currentAPI, err := h.getApiDef(id)

		if err != nil {
			log.WithError(err).Errorf("Could not retrieve API version detail for id: %s", id)
			continue
		}

		if !canInclude(currentAPI, name) {
			continue
		}

		versionMetas.Metas = append(versionMetas.Metas, VersionMeta{
			ID:			id,
			Name:			currentAPI.Name,
			VersionName:		name,
			Internal:		currentAPI.Internal,
			ExpirationDate:		currentAPI.Expiration,
			IsDefaultVersion:	baseAPI.VersionDefinition.Default == name,
		})
	}

	sort.Slice(versionMetas.Metas, func(i, j int) bool {
		return versionMetas.Metas[i].VersionName < versionMetas.Metas[j].VersionName
	})

	if canInclude(baseAPI, baseAPI.VersionDefinition.Name) {
		versionMetas.Metas = append([]VersionMeta{{
			ID:			baseAPI.APIID,
			Name:			baseAPI.Name,
			VersionName:		baseAPI.VersionDefinition.Name,
			Internal:		baseAPI.Internal,
			ExpirationDate:		baseAPI.Expiration,
			IsDefaultVersion:	baseAPI.VersionDefinition.Default == baseAPI.VersionDefinition.Name,
		}}, versionMetas.Metas...)
	}

	versionMetas.Status = "success"

	doJSONWrite(w, http.StatusOK, versionMetas)
}

Cognitive complexity: 22, Cyclomatic complexity: 11

Uses: apidef.APIDefinition, http.StatusNotFound, http.StatusOK, mux.Vars, sort.Slice, strings.Contains, strings.ToLower.

func (*VirtualEndpoint) EnabledForSpec

func (d *VirtualEndpoint) EnabledForSpec() bool {
	if !d.Spec.GlobalConfig.EnableJSVM {
		return false
	}

	return d.Spec.hasVirtualEndpoint()
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*VirtualEndpoint) HandleResponse

func (d *VirtualEndpoint) HandleResponse(rw http.ResponseWriter, res *http.Response, ses *user.SessionState) {
	// Externalising this from the MW so we can re-use it elsewhere
	d.Gw.handleForcedResponse(rw, res, ses, d.Spec)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*VirtualEndpoint) Init

func (d *VirtualEndpoint) Init() {
	d.sh = SuccessHandler{d.BaseMiddleware}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*VirtualEndpoint) Name

func (d *VirtualEndpoint) Name() string {
	return "VirtualEndpoint"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*VirtualEndpoint) ProcessRequest

ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail

func (d *VirtualEndpoint) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	vmeta := d.getMetaFromRequest(r)
	if vmeta == nil {
		// nothing can be done here, reply with 200 to allow proxy to target
		return nil, http.StatusOK
	}

	if _, err := d.ServeHTTPForCache(w, r, vmeta); err != nil {
		message := "Error during virtual endpoint execution. Contact Administrator for more details."
		d.Logger().WithError(err).WithField("vmeta", vmeta).Error(message)

		if vmeta.ProxyOnError {
			return nil, http.StatusOK
		}

		return errors.New(message), http.StatusInternalServerError
	}

	return nil, mwStatusRespond
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: errors.New, http.StatusInternalServerError, http.StatusOK.

func (*VirtualEndpoint) ServeHTTPForCache

func (d *VirtualEndpoint) ServeHTTPForCache(w http.ResponseWriter, r *http.Request, vmeta *apidef.VirtualMeta) (*http.Response, error) {
	t1 := time.Now()
	if vmeta == nil {
		if vmeta = d.getMetaFromRequest(r); vmeta == nil {
			return nil, errors.New("No request info")
		}
	}

	// Create the proxy object
	originalBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read request body: %w", err)
	}
	defer r.Body.Close()

	scheme := "http"
	if r.TLS != nil {
		scheme = "https"
	}
	requestData := RequestObject{
		Headers:	r.Header,
		Body:		string(originalBody),
		URL:		r.URL.String(),
		Scheme:		scheme,
	}

	// We need to copy the body _back_ for the decode
	r.Body = ioutil.NopCloser(bytes.NewReader(originalBody))
	parseForm(r)
	requestData.Params = r.Form

	requestAsJson, err := json.Marshal(requestData)
	if err != nil {
		return nil, fmt.Errorf("failed to encode request object for virtual endpoint: %w", err)
	}

	// Encode the configuration data too
	specAsJson := specToJson(d.Spec)

	session := new(user.SessionState)

	// Encode the session object (if not a pre-process)
	if vmeta.UseSession {
		session = ctxGetSession(r)
	}

	sessionAsJson, err := json.Marshal(session)
	if err != nil {
		return nil, fmt.Errorf("failed to encode session for VM: %w", err)
	}

	// Run the middleware

	vm := d.Spec.JSVM.VM.Copy()
	vm.Interrupt = make(chan func(), 1)
	d.Logger().Debug("Running: ", vmeta.ResponseFunctionName)
	// buffered, leaving no chance of a goroutine leak since the
	// spawned goroutine will send 0 or 1 values.
	ret := make(chan otto.Value, 1)
	errRet := make(chan error, 1)
	go func() {
		defer func() {
			// the VM executes the panic func that gets it
			// to stop, so we must recover here to not crash
			// the whole Go program.
			recover()
		}()
		returnRaw, err := vm.Run(vmeta.ResponseFunctionName + `(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`)
		ret <- returnRaw
		errRet <- err
	}()
	var returnRaw otto.Value
	t := time.NewTimer(d.Spec.JSVM.Timeout)
	select {
	case returnRaw = <-ret:
		if err := <-errRet; err != nil {
			return nil, fmt.Errorf("Failed to run JS middleware: %w", err)
		}
		t.Stop()
	case <-t.C:
		t.Stop()
		d.Logger().Error("JS middleware timed out after ", d.Spec.JSVM.Timeout)
		vm.Interrupt <- func() {
			// only way to stop the VM is to send it a func
			// that panics.
			panic("stop")
		}
		return nil, fmt.Errorf("JS middleware timed out after %s", d.Spec.JSVM.Timeout)
	}
	returnDataStr, _ := returnRaw.ToString()

	// Decode the return object
	newResponseData := VMResponseObject{}
	if err := json.Unmarshal([]byte(returnDataStr), &newResponseData); err != nil {
		d.Logger().WithError(err).WithField("return_data", returnDataStr).Errorf("Failed to decode virtual endpoint response data on return from VM")
		return nil, fmt.Errorf("Failed to decode virtual endpoint response: %w", err)
	}

	// Save the sesison data (if modified)
	if vmeta.UseSession {
		newMeta := newResponseData.SessionMeta
		if !reflect.DeepEqual(session.MetaData, newMeta) {
			session.MetaData = newMeta
			ctxSetSession(r, session, true, d.Gw.GetConfig().HashKeys)
		}
	}

	copiedResponse := d.Gw.forceResponse(w, r, &newResponseData, d.Spec, session, false, d.Logger())
	ms := DurationToMillisecond(time.Since(t1))
	d.Logger().Debug("JSVM Virtual Endpoint execution took: (ms) ", ms)

	if copiedResponse != nil {
		d.sh.RecordHit(r, analytics.Latency{Total: int64(ms)}, copiedResponse.StatusCode, copiedResponse, false)
	}

	return copiedResponse, nil
}

Cognitive complexity: 33, Cyclomatic complexity: 15

Uses: analytics.Latency, bytes.NewReader, errors.New, fmt.Errorf, ioutil.NopCloser, ioutil.ReadAll, json.Marshal, json.Unmarshal, otto.Value, reflect.DeepEqual, time.NewTimer, time.Now, time.Since, user.SessionState.

func (*WebHookHandler) BuildRequest

func (w *WebHookHandler) BuildRequest(reqBody string) (*http.Request, error) {
	req, err := http.NewRequest(string(w.getRequestMethod(w.conf.Method)), w.conf.TargetPath, strings.NewReader(reqBody))
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "webhooks",
		}).Error("Failed to create request object: ", err)
		return nil, err
	}

	req.Header.Set(header.UserAgent, header.TykHookshot)

	ignoreCanonical := w.Gw.GetConfig().IgnoreCanonicalMIMEHeaderKey
	for key, val := range w.conf.HeaderList {
		setCustomHeader(req.Header, key, val, ignoreCanonical)
	}

	if req.Header.Get(header.ContentType) == "" {
		req.Header.Set(header.ContentType, w.contentType)
	}

	return req, nil
}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: header.ContentType, header.TykHookshot, header.UserAgent, http.NewRequest, logrus.Fields, strings.NewReader.

func (*WebHookHandler) Checksum

func (w *WebHookHandler) Checksum(reqBody string) (string, error) {
	// We do this twice because fuck it.
	localRequest, _ := http.NewRequest(string(w.getRequestMethod(w.conf.Method)), w.conf.TargetPath, strings.NewReader(reqBody))
	h := md5.New()
	localRequest.Write(h)
	return hex.EncodeToString(h.Sum(nil)), nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: hex.EncodeToString, http.NewRequest, md5.New, strings.NewReader.

func (*WebHookHandler) CreateBody

CreateBody will render the webhook event message template and return it as a string. If an error occurs, an empty string will be returned alongside an error.

func (w *WebHookHandler) CreateBody(em config.EventMessage) (string, error) {
	var reqBody bytes.Buffer
	err := w.template.Execute(&reqBody, em)
	if err != nil {
		return "", err
	}
	return reqBody.String(), err
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: bytes.Buffer.

func (*WebHookHandler) HandleEvent

HandleEvent will be fired when the event handler instance is found in an APISpec EventPaths object during a request chain

func (w *WebHookHandler) HandleEvent(em config.EventMessage) {

	// Inject event message into template, render to string
	reqBody, err := w.CreateBody(em)
	if err != nil {
		// We're just logging the template rendering issue here
		// but we're passing on the partial rendered contents
		log.WithError(err).WithFields(logrus.Fields{
			"prefix": "webhooks",
		}).Error("Webhook template rendering error")
		return
	}

	// Construct request (method, body, params)
	req, err := w.BuildRequest(reqBody)
	if err != nil {
		return
	}

	// Generate signature for request
	reqChecksum, _ := w.Checksum(reqBody)

	// Check request velocity for this hook (wasHookFired())
	if w.WasHookFired(reqChecksum) {
		return
	}

	cli := &http.Client{Timeout: 30 * time.Second}

	resp, err := cli.Do(req)
	if err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "webhooks",
		}).Error("Webhook request failed: ", err)
	} else {
		defer resp.Body.Close()
		if resp.StatusCode >= 200 && resp.StatusCode < 300 {
			content, err := ioutil.ReadAll(resp.Body)
			if err == nil {
				log.WithFields(logrus.Fields{
					"prefix":	"webhooks",
					"responseCode":	resp.StatusCode,
				}).Debug(string(content))
			} else {
				log.WithFields(logrus.Fields{
					"prefix": "webhooks",
				}).Error(err)
			}

		} else {
			log.WithFields(logrus.Fields{
				"prefix":	"webhooks",
				"responseCode":	resp.StatusCode,
			}).Error("Request to webhook failed")
		}
	}

	if w.dashboardService != nil && em.Type == EventTriggerExceeded {
		w.dashboardService.NotifyDashboardOfEvent(em.Meta)
	}

	w.setHookFired(reqChecksum)
}

Cognitive complexity: 26, Cyclomatic complexity: 10

Uses: http.Client, ioutil.ReadAll, logrus.Fields, time.Second.

func (*WebHookHandler) Init

Init enables the init of event handler instances when they are created on ApiSpec creation

func (w *WebHookHandler) Init(handlerConf interface{}) error {
	var err error
	if err = w.conf.Scan(handlerConf); err != nil {
		log.WithFields(logrus.Fields{
			"prefix": "webhooks",
		}).Error("Problem getting configuration, skipping. ", err)
		return err
	}

	if w.conf.Disabled {
		log.WithFields(logrus.Fields{
			"prefix": "webhooks",
		}).Infof("skipping disabled webhook %s", w.conf.Name)
		return ErrEventHandlerDisabled
	}

	w.store = &storage.RedisCluster{KeyPrefix: "webhook.cache.", ConnectionHandler: w.Gw.StorageConnectionHandler}
	w.store.Connect()

	// Pre-load template on init
	if w.conf.TemplatePath != "" {
		w.template, err = htmltemplate.ParseFiles(w.conf.TemplatePath)
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix":	"webhooks",
				"target":	w.conf.TargetPath,
			}).Warning("Custom template load failure, using default: ", err)
		}

		if strings.HasSuffix(w.conf.TemplatePath, ".json") {
			w.contentType = header.ApplicationJSON
		}
	}

	// We use the default if TemplatePath was empty or if we failed
	// to load it.
	if w.template == nil {
		log.WithFields(logrus.Fields{
			"prefix":	"webhooks",
			"target":	w.conf.TargetPath,
		}).Info("Loading default template.")
		defaultPath := filepath.Join(w.Gw.GetConfig().TemplatePath, "default_webhook.json")
		w.template, err = htmltemplate.ParseFiles(defaultPath)
		if err != nil {
			log.WithFields(logrus.Fields{
				"prefix": "webhooks",
			}).Error("Could not load the default template: ", err)
			return err
		}
		w.contentType = header.ApplicationJSON
	}

	log.WithFields(logrus.Fields{
		"prefix": "webhooks",
	}).Debug("Timeout set to: ", w.conf.EventTimeout)

	if !w.checkURL(w.conf.TargetPath) {
		log.WithFields(logrus.Fields{
			"prefix": "webhooks",
		}).Error("Init failed for this webhook, invalid URL, URL must be absolute")
	}

	if w.Gw.GetConfig().UseDBAppConfigs {
		dashboardServiceInit(w.Gw)
		w.dashboardService = w.Gw.DashService
	}

	return nil
}

Cognitive complexity: 27, Cyclomatic complexity: 10

Uses: filepath.Join, header.ApplicationJSON, htmltemplate.ParseFiles, logrus.Fields, storage.RedisCluster, strings.HasSuffix.

func (*WebHookHandler) WasHookFired

hookFired checks if an event has been fired within the EventTimeout setting

func (w *WebHookHandler) WasHookFired(checksum string) bool {
	if _, err := w.store.GetKey(checksum); err != nil {
		// Key not found, so hook is in limit
		log.WithFields(logrus.Fields{
			"prefix": "webhooks",
		}).Debug("Event can fire, no duplicates found")
		return false
	}

	return true
}

Cognitive complexity: 3, Cyclomatic complexity: 2

Uses: logrus.Fields.

func (*XPathExtractor) ExtractAndCheck

func (e *XPathExtractor) ExtractAndCheck(r *http.Request) (SessionID string, returnOverrides ReturnOverrides) {
	var err error

	if e.IDExtractorConfig.XPathExpression == "" {
		returnOverrides = e.Error(r, err, "XPathExtractor: no expression set")
		return SessionID, returnOverrides
	}

	if e.path == nil {
		expressionString := e.IDExtractorConfig.XPathExpression
		e.path, err = xmlpath.Compile(expressionString)
		if err != nil {
			returnOverrides = e.Error(r, err, "XPathExtractor: bad expression")
			return SessionID, returnOverrides
		}
	}

	var extractorOutput string
	switch e.Config.ExtractFrom {
	case apidef.HeaderSource:
		extractorOutput, err = e.ExtractHeader(r)
	case apidef.BodySource:
		extractorOutput, err = e.ExtractBody(r)
	case apidef.FormSource:
		extractorOutput, err = e.ExtractForm(r, e.IDExtractorConfig.FormParamName)
	}
	if err != nil {
		returnOverrides = e.Error(r, err, "XPathExtractor error")
		return SessionID, returnOverrides
	}

	extractedXml, err := xmlpath.Parse(strings.NewReader(extractorOutput))
	if err != nil {
		returnOverrides = e.Error(r, err, "XPathExtractor: couldn't parse input")
		return SessionID, returnOverrides
	}

	output, ok := e.path.String(extractedXml)
	if !ok {
		returnOverrides = e.Error(r, err, "XPathExtractor: no input")
		return SessionID, returnOverrides
	}

	SessionID = e.GenerateSessionID(output, e.BaseMiddleware)
	previousSession, keyExists := e.BaseMiddleware.CheckSessionAndIdentityForValidKey(SessionID, r)
	SessionID = previousSession.KeyID

	if keyExists {
		if previousSession.IdExtractorDeadline > time.Now().Unix() {
			ctxSetSession(r, &previousSession, true, e.Gw.GetConfig().HashKeys)
			returnOverrides = ReturnOverrides{
				ResponseCode: 200,
			}
		}
	}

	return SessionID, returnOverrides
}

Cognitive complexity: 22, Cyclomatic complexity: 13

Uses: apidef.BodySource, apidef.FormSource, apidef.HeaderSource, strings.NewReader, time.Now, xmlpath.Compile, xmlpath.Parse.

func (*customResponseWriter) Flush

func (w *customResponseWriter) Flush() {
	if flusher, ok := w.ResponseWriter.(http.Flusher); ok {
		flusher.Flush()
	}
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: http.Flusher.

func (*customResponseWriter) Write

func (w *customResponseWriter) Write(b []byte) (int, error) {
	w.responseSent = true
	if w.statusCodeSent == 0 {
		w.statusCodeSent = http.StatusOK	// no WriteHeader was called so it will be set to StatusOK in actual ResponseWriter
	}

	// send actual data
	num, err := w.ResponseWriter.Write(b)

	// copy data sent
	if w.copyData {
		if w.data == nil {
			w.data = make([]byte, num)
			copy(w.data, b[:num])
		} else {
			w.data = append(w.data, b[:num]...)
		}
	}

	// count how many bytes we sent
	w.dataLength += int64(num)

	return num, err
}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: http.StatusOK.

func (*customResponseWriter) WriteHeader

func (w *customResponseWriter) WriteHeader(statusCode int) {
	w.responseSent = true
	w.statusCodeSent = statusCode
	w.ResponseWriter.WriteHeader(statusCode)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*dummyStreamingMiddleware) EnabledForSpec

func (d *dummyStreamingMiddleware) EnabledForSpec() bool {
	streamingConfig := d.Gw.GetConfig().Streaming

	if streamingConfig.Enabled && d.Spec.isStreamingAPI() {
		d.Logger().Warnf("Warning: %s", MessageStreamingOnlySupportedInEE)
		return true
	}

	return false
}

Cognitive complexity: 2, Cyclomatic complexity: 3

func (*dummyStreamingMiddleware) Name

func (d *dummyStreamingMiddleware) Name() string {
	return "StreamingMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*dummyStreamingMiddleware) ProcessRequest

func (d *dummyStreamingMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	failHttpCode := http.StatusForbidden
	d.Logger().WithField("status_code", failHttpCode).Errorf("Error: %s", MessageStreamingOnlySupportedInEE)
	return ee.ErrActionNotAllowed, failHttpCode
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: ee.ErrActionNotAllowed, http.StatusForbidden.

func (*explicitRouteHandler) ServeHTTP

func (h *explicitRouteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == h.prefix || strings.HasPrefix(r.URL.Path, h.prefix+"/") {
		h.handler.ServeHTTP(w, r)
		return
	}

	w.WriteHeader(http.StatusNotFound)
	_, _ = fmt.Fprint(w, http.StatusText(http.StatusNotFound))
}

Cognitive complexity: 2, Cyclomatic complexity: 3

Uses: fmt.Fprint, http.StatusNotFound, http.StatusText, strings.HasPrefix.

func (*h2cWrapper) ServeHTTP

func (h *h2cWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.h.ServeHTTP(w, r)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*handleWrapper) ServeHTTP

func (h *handleWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Body != nil {
		if !h.handleRequestLimits(w, r) {
			return
		}
	}

	if h.maxRequestBodySize > 0 {
		// this greedily reads in the request body and
		// make request body to be nopCloser and re-readable
		// before serve it through chain of middlewares
		if err := nopCloseRequestBodyErr(r); err != nil {
			if err.Error() == "http: request body too large" {
				httputil.EntityTooLarge(w, r)
				return
			}

			httputil.InternalServerError(w, r)
			return
		}
	} else {
		// this leaves the body on lazy read as before
		if _, err := copyRequest(r); err != nil {
			log.WithError(err).Error("Error reading request body")
			httputil.InternalServerError(w, r)
		}
	}

	// Test don't provide a router
	if h.router == nil {
		return
	}

	h.router.ServeHTTP(w, r)
}

Cognitive complexity: 16, Cyclomatic complexity: 8

Uses: httputil.EntityTooLarge, httputil.InternalServerError.

func (*httpProxyHandler) Stop

func (p *httpProxyHandler) Stop(s *Test) error {
	return p.server.Close()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*introspectionCache) GetRes

func (c *introspectionCache) GetRes(token string) (jwt.MapClaims, bool) {
	var claims jwt.MapClaims
	claimsStr, err := c.GetKey(token)
	if err != nil {
		return nil, false
	}

	err = json.Unmarshal([]byte(claimsStr), &claims)
	if err != nil {
		return nil, false
	}

	return claims, true
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: json.Unmarshal.

func (*introspectionCache) SetRes

func (c *introspectionCache) SetRes(token string, res jwt.MapClaims, timeout int64) error {
	claimsInBytes, err := json.Marshal(res)
	if err != nil {
		return err
	}

	return c.SetKey(token, string(claimsInBytes), timeout)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: json.Marshal.

func (*maxLatencyWriter) Write

func (m *maxLatencyWriter) Write(p []byte) (n int, err error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	n, err = m.dst.Write(p)
	if m.latency < 0 {
		m.dst.Flush()
		return
	}
	if m.flushPending {
		return
	}
	if m.t == nil {
		m.t = time.AfterFunc(m.latency, m.delayedFlush)
	} else {
		m.t.Reset(m.latency)
	}
	m.flushPending = true
	return
}

Cognitive complexity: 8, Cyclomatic complexity: 4

Uses: time.AfterFunc.

func (*noopUpstreamBasicAuth) EnabledForSpec

EnabledForSpec will always return false for noopUpstreamBasicAuth.

func (d *noopUpstreamBasicAuth) EnabledForSpec() bool {
	if d.Spec.UpstreamAuth.BasicAuth.Enabled {
		d.Logger().Error("Upstream basic auth is supported only in Tyk Enterprise Edition")
	}

	return false
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*noopUpstreamBasicAuth) Name

Name returns the name of the mw.

func (d *noopUpstreamBasicAuth) Name() string {
	return "NooPUpstreamBasicAuth"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*noopUpstreamBasicAuth) ProcessRequest

ProcessRequest is noop implementation for upstream basic auth mw.

func (d *noopUpstreamBasicAuth) ProcessRequest(_ http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
	return nil, http.StatusOK
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: http.StatusOK.

func (*noopUpstreamOAuth) EnabledForSpec

EnabledForSpec will always return false for noopUpstreamOAuth.

func (d *noopUpstreamOAuth) EnabledForSpec() bool {
	if d.Spec.UpstreamAuth.OAuth.Enabled {
		d.Logger().Error("Upstream OAuth is supported only in Tyk Enterprise Edition")
	}

	return false
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*noopUpstreamOAuth) Name

Name returns the name of the mw.

func (d *noopUpstreamOAuth) Name() string {
	return "NooPUpstreamOAuth"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*noopUpstreamOAuth) ProcessRequest

ProcessRequest is noop implementation for upstream OAuth mw.

func (d *noopUpstreamOAuth) ProcessRequest(_ http.ResponseWriter, _ *http.Request, _ interface{}) (error, int) {
	return nil, http.StatusOK
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: http.StatusOK.

func (*nopCloserBuffer) Close

Close is a no-op Close

func (n *nopCloserBuffer) Close() error {
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*nopCloserBuffer) Read

Read just a wrapper around real Read which also moves position to the start if we get EOF to have it ready for next read-cycle

func (n *nopCloserBuffer) Read(p []byte) (int, error) {
	if err := n.copy(); err != nil {
		return 0, err
	}

	idx := n.position
	num, err := bytes.NewBuffer(n.buf.Bytes()[idx:]).Read(p)

	if err == nil {
		cnt := int64(n.buf.Len())
		if idx+int64(len(p)) < cnt {
			n.position += int64(len(p))
		} else {
			n.position = cnt
		}
	}

	// move to start to have it ready for next read cycle
	if errors.Is(err, io.EOF) {
		_, seekErr := n.Seek(0, io.SeekStart)
		if seekErr != nil {
			log.WithError(seekErr).Error("can't rewind nopCloserBuffer")
		}
	}

	return num, err
}

Cognitive complexity: 12, Cyclomatic complexity: 6

Uses: bytes.NewBuffer, errors.Is, io.EOF, io.SeekStart.

func (*nopCloserBuffer) Seek

Seek seeks within the buffer

func (n *nopCloserBuffer) Seek(offset int64, whence int) (int64, error) {
	if whence != io.SeekStart {
		return 0, errors.New("invalid seek method, only supporting SeekStart")
	}

	if offset == 0 && n.position == 0 {
		return 0, nil
	}

	if err := n.copy(); err != nil {
		return 0, err
	}

	cnt := int64(n.buf.Len())

	if offset >= cnt || offset < 0 {
		return 0, errors.New("invalid seek offset")
	}

	n.position = offset

	return offset, nil
}

Cognitive complexity: 8, Cyclomatic complexity: 7

Uses: errors.New, io.SeekStart.

func (*redisChannelHook) Fire

func (hook *redisChannelHook) Fire(entry *logrus.Entry) error {
	orgId, found := entry.Data["org_id"]
	if !found {
		return nil
	}

	newEntry, err := hook.formatter.Format(entry)
	if err != nil {
		log.Error(err)
		return nil
	}

	msg := string(newEntry)

	n := InterfaceNotification{
		Type:		"gateway-log",
		Message:	msg,
		OrgID:		orgId.(string),
		Timestamp:	time.Now(),
	}

	go hook.notifier.Notify(n)

	return nil
}

Cognitive complexity: 5, Cyclomatic complexity: 3

Uses: time.Now.

func (*redisChannelHook) Levels

func (hook *redisChannelHook) Levels() []logrus.Level {
	return []logrus.Level{
		logrus.InfoLevel,
		logrus.ErrorLevel,
		logrus.FatalLevel,
		logrus.PanicLevel,
	}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: logrus.ErrorLevel, logrus.FatalLevel, logrus.InfoLevel, logrus.Level, logrus.PanicLevel.

func (*testMessageAdapter) Channel

Channel returns the channel the message was received on.

func (m *testMessageAdapter) Channel() (string, error) {
	return "", nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*testMessageAdapter) Payload

Payload returns the message payload.

func (m *testMessageAdapter) Payload() (string, error) {
	return m.Msg, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*testMessageAdapter) Type

Type returns the message type.

func (m *testMessageAdapter) Type() string {
	return "message"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*variableReplaceRoundTripper) RoundTrip

func (d *variableReplaceRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	for key := range req.Header {
		val := d.gw.ReplaceTykVariables(d.outReq, req.Header.Get(key), false)
		req.Header.Set(key, val)
	}

	return d.next.RoundTrip(req)
}

Cognitive complexity: 3, Cyclomatic complexity: 2

func (*wrapMiddleware) Base

func (w *wrapMiddleware) Base() *BaseMiddleware {
	return w.BaseMiddleware
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*wrapMiddleware) Config

func (w *wrapMiddleware) Config() (interface{}, error) {
	return w.BaseMiddleware.Config()
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*wrapMiddleware) EnabledForSpec

func (w *wrapMiddleware) EnabledForSpec() bool {
	return w.mw.EnabledForSpec()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*wrapMiddleware) Init

func (w *wrapMiddleware) Init() {
	w.mw.Init()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*wrapMiddleware) Logger

func (w *wrapMiddleware) Logger() *logrus.Entry {
	return w.mw.Logger()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*wrapMiddleware) Name

func (w *wrapMiddleware) Name() string {
	return w.mw.Name()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*wrapMiddleware) ProcessRequest

func (w *wrapMiddleware) ProcessRequest(rw http.ResponseWriter, r *http.Request, data interface{}) (error, int) {
	return w.mw.ProcessRequest(rw, r, data)
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (*wrapMiddleware) Unload

func (w *wrapMiddleware) Unload() {
	w.mw.Unload()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (APIDefinitionLoader) FromDashboardService

FromDashboardService will connect and download ApiDefintions from a Tyk Dashboard instance.

func (a APIDefinitionLoader) FromDashboardService(endpoint string) ([]*APISpec, error) {
	// Get the definitions
	log.Debug("Calling: ", endpoint)
	newRequest, err := http.NewRequest("GET", endpoint, nil)
	if err != nil {
		log.Error("Failed to create request: ", err)
	}

	gwConfig := a.Gw.GetConfig()

	newRequest.Header.Set("authorization", gwConfig.NodeSecret)
	log.Debug("Using: NodeID: ", a.Gw.GetNodeID())
	newRequest.Header.Set(header.XTykNodeID, a.Gw.GetNodeID())

	a.Gw.ServiceNonceMutex.RLock()
	newRequest.Header.Set(header.XTykNonce, a.Gw.ServiceNonce)
	a.Gw.ServiceNonceMutex.RUnlock()

	newRequest.Header.Set(header.XTykSessionID, a.Gw.SessionID)

	c := a.Gw.initialiseClient()
	resp, err := c.Do(newRequest)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode == http.StatusForbidden {
		body, _ := ioutil.ReadAll(resp.Body)
		return nil, fmt.Errorf("login failure, Response was: %v", string(body))
	}

	if resp.StatusCode != http.StatusOK {
		body, _ := ioutil.ReadAll(resp.Body)
		return nil, fmt.Errorf("dashboard API error, response was: %v", string(body))
	}

	// Extract tagged APIs#
	list := model.NewMergedAPIList()
	inBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Error("Couldn't read api definition list")
		return nil, err
	}

	inBytes = a.replaceSecrets(inBytes)

	err = json.Unmarshal(inBytes, &list)
	if err != nil {
		log.Error("Couldn't unmarshal api definition list")
		return nil, err
	}

	// Extract tagged entries only
	apiDefs := list.Filter(gwConfig.DBAppConfOptions.NodeIsSegmented, gwConfig.DBAppConfOptions.Tags...)

	// Process
	specs := a.prepareSpecs(apiDefs, gwConfig, false)

	// Set the nonce
	a.Gw.ServiceNonceMutex.Lock()
	a.Gw.ServiceNonce = list.Nonce
	a.Gw.ServiceNonceMutex.Unlock()
	log.Debug("Loading APIS Finished: Nonce Set: ", list.Nonce)

	return specs, nil
}

Cognitive complexity: 12, Cyclomatic complexity: 7

Uses: fmt.Errorf, header.XTykNodeID, header.XTykNonce, header.XTykSessionID, http.NewRequest, http.StatusForbidden, http.StatusOK, io.ReadAll, ioutil.ReadAll, json.Unmarshal, model.NewMergedAPIList.

func (APIDefinitionLoader) FromDir

FromDir will load APIDefinitions from a directory on the filesystem. Definitions need to be the JSON representation of APIDefinition object

func (a APIDefinitionLoader) FromDir(dir string) []*APISpec {
	var specs []*APISpec
	// Grab json files from directory
	paths, _ := filepath.Glob(filepath.Join(dir, "*.json"))
	for _, path := range paths {
		if strings.HasSuffix(path, "-oas.json") {
			continue
		}

		spec, err := a.loadDefFromFilePath(path)

		if err != nil {
			continue
		}

		specs = append(specs, spec)
	}
	return specs
}

Cognitive complexity: 7, Cyclomatic complexity: 4

Uses: filepath.Glob, filepath.Join, strings.HasSuffix.

func (APIDefinitionLoader) FromRPC

FromCloud will connect and download ApiDefintions from a Mongo DB instance.

func (a APIDefinitionLoader) FromRPC(store RPCDataLoader, orgId string, gw *Gateway) ([]*APISpec, error) {
	if rpc.IsEmergencyMode() {
		return gw.LoadDefinitionsFromRPCBackup()
	}

	if !store.Connect() {
		return nil, errors.New("Can't connect RPC layer")
	}

	// enable segments
	var tags []string
	if gw.GetConfig().DBAppConfOptions.NodeIsSegmented {
		log.Info("Segmented node, loading: ", gw.GetConfig().DBAppConfOptions.Tags)
		tags = gw.GetConfig().DBAppConfOptions.Tags
	}

	apiCollection := store.GetApiDefinitions(orgId, tags)
	apiCollection = string(a.replaceSecrets([]byte(apiCollection)))

	//store.Disconnect()

	if rpc.LoadCount() > 0 {
		if err := gw.saveRPCDefinitionsBackup(apiCollection); err != nil {
			log.Error(err)
		}
	}

	return a.processRPCDefinitions(apiCollection, gw)
}

Cognitive complexity: 10, Cyclomatic complexity: 6

Uses: errors.New, rpc.IsEmergencyMode, rpc.LoadCount.

func (APIDefinitionLoader) GetOASFilepath

func (a APIDefinitionLoader) GetOASFilepath(path string) string {
	return strings.TrimSuffix(path, ".json") + "-oas.json"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: strings.TrimSuffix.

func (APIDefinitionLoader) MakeSpec

MakeSpec will generate a flattened URLSpec from and APIDefinitions' VersionInfo data. paths are keyed to the Api version name, which is determined during routing to speed up lookups

func (a APIDefinitionLoader) MakeSpec(def *model.MergedAPI, logger *logrus.Entry) (*APISpec, error) {
	if logger == nil {
		logger = logrus.NewEntry(log).WithFields(logrus.Fields{
			"api_id":	def.APIID,
			"org_id":	def.OrgID,
			"name":		def.Name,
		})
	}

	spec := &APISpec{}
	apiString, err := json.Marshal(def)
	if err != nil {
		logger.WithError(err).Error("Failed to JSON marshal API definition")
		return nil, err
	}

	sha256hash := sha256.Sum256(apiString)
	// Unique API content ID, to check if we already have if it changed from previous sync
	spec.Checksum = base64.URLEncoding.EncodeToString(sha256hash[:])

	spec.APIDefinition = def.APIDefinition

	if currSpec := a.Gw.getApiSpec(def.APIID); !shouldReloadSpec(currSpec, spec) {
		return currSpec, nil
	}

	// new expiration feature
	if def.Expiration != "" {
		if t, err := time.Parse(apidef.ExpirationTimeFormat, def.Expiration); err != nil {
			logger.WithError(err).WithField("Expiration", def.Expiration).Error("Could not parse expiration date for API")
		} else {
			def.ExpirationTs = t
		}
	}

	// Deprecated
	// parse version expiration time stamps
	for key, ver := range def.VersionData.Versions {
		if ver.Expires == "" || ver.Expires == "-1" {
			continue
		}
		// calculate the time
		if t, err := time.Parse(apidef.ExpirationTimeFormat, ver.Expires); err != nil {
			logger.WithError(err).WithField("expires", ver.Expires).Error("Could not parse expiry date for API")
		} else {
			ver.ExpiresTs = t
			def.VersionData.Versions[key] = ver
		}
	}

	// We'll push the default HealthChecker:
	spec.Health = &DefaultHealthChecker{
		Gw:	a.Gw,
		APIID:	spec.APIID,
	}

	// Add any new session managers or auth handlers here
	spec.AuthManager = &DefaultSessionManager{Gw: a.Gw}
	spec.OrgSessionManager = &DefaultSessionManager{
		orgID:	spec.OrgID,
		Gw:	a.Gw,
	}

	spec.GlobalConfig = a.Gw.GetConfig()

	if err = a.Gw.loadBundle(spec); err != nil {
		logger.WithError(err).Error("Couldn't load bundle")
		return nil, err
	}

	if a.Gw.GetConfig().EnableJSVM && (spec.hasVirtualEndpoint() || spec.CustomMiddleware.Driver == apidef.OttoDriver) {
		logger.Debug("Initializing JSVM")
		spec.JSVM.Init(spec, logger, a.Gw)
	}

	// Set up Event Handlers
	if len(def.EventHandlers.Events) > 0 {
		logger.Debug("Initializing event handlers")
	}
	spec.EventPaths = make(map[apidef.TykEvent][]config.TykEventHandler)
	for eventName, eventHandlerConfs := range def.EventHandlers.Events {
		logger.Debug("FOUND EVENTS TO INIT")
		for _, handlerConf := range eventHandlerConfs {
			logger.Debug("CREATING EVENT HANDLERS")
			eventHandlerInstance, err := a.Gw.EventHandlerByName(handlerConf, spec)

			if err != nil {
				logger.Error("Failed to init event handler: ", err)
			} else {
				logger.Debug("Init Event Handler: ", eventName)
				spec.EventPaths[eventName] = append(spec.EventPaths[eventName], eventHandlerInstance)
			}
		}
	}

	spec.RxPaths = make(map[string][]URLSpec, len(def.VersionData.Versions))
	spec.WhiteListEnabled = make(map[string]bool, len(def.VersionData.Versions))
	for _, v := range def.VersionData.Versions {
		var pathSpecs []URLSpec
		var whiteListSpecs bool

		// If we have transitioned to extended path specifications, we should use these now
		if v.UseExtendedPaths {
			pathSpecs, whiteListSpecs = a.getExtendedPathSpecs(v, spec, a.Gw.GetConfig())
		} else {
			logger.Warning("Legacy path detected! Upgrade to extended.")
			pathSpecs, whiteListSpecs = a.getPathSpecs(v, a.Gw.GetConfig())
		}
		spec.RxPaths[v.Name] = pathSpecs
		spec.WhiteListEnabled[v.Name] = whiteListSpecs
	}

	if spec.IsOAS && def.OAS != nil {
		loader := openapi3.NewLoader()
		if err := loader.ResolveRefsIn(&def.OAS.T, nil); err != nil {
			logger.WithError(err).Errorf("Dashboard loaded API's OAS reference resolve failed: %s", def.APIID)
		}

		spec.OAS = *def.OAS
	}

	if err := httputil.ValidatePath(spec.Proxy.ListenPath); err != nil {
		logger.WithError(err).Error("Invalid listen path when creating router")
		return nil, err
	}

	oasSpec := spec.OAS.T
	oasSpec.Servers = openapi3.Servers{
		{URL: spec.Proxy.ListenPath},
	}

	spec.OASRouter, err = gorillamux.NewRouter(&oasSpec)
	if err != nil {
		logger.WithError(err).Error("Could not create OAS router")
	}

	spec.setHasMock()

	return spec, nil
}

Cognitive complexity: 59, Cyclomatic complexity: 25

Uses: apidef.ExpirationTimeFormat, apidef.OttoDriver, apidef.TykEvent, base64.URLEncoding, config.TykEventHandler, gorillamux.NewRouter, httputil.ValidatePath, json.Marshal, logrus.Fields, logrus.NewEntry, openapi3.NewLoader, openapi3.Servers, sha256.Sum256, time.Parse.

func (APIDefinitionLoader) ParseDefinition

func (a APIDefinitionLoader) ParseDefinition(r io.Reader) (api apidef.APIDefinition) {
	if err := json.NewDecoder(r).Decode(&api); err != nil {
		log.Error("Couldn't unmarshal api configuration: ", err)
	}

	return
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: json.NewDecoder.

func (APIDefinitionLoader) ParseOAS

func (a APIDefinitionLoader) ParseOAS(r io.Reader) (oas oas.OAS) {
	if err := json.NewDecoder(r).Decode(&oas); err != nil {
		log.Error("Couldn't unmarshal oas configuration: ", err)
	}

	return
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: json.NewDecoder.

func (CustomMiddlewareResponseHook) Base

func (h CustomMiddlewareResponseHook) Base() *BaseTykResponseHandler {
	return &h.BaseTykResponseHandler
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (DefaultKeyGenerator) GenerateAuthKey

GenerateAuthKey is a utility function for generating new auth keys. Returns the storage key name and the actual key

func (d DefaultKeyGenerator) GenerateAuthKey(orgID string) string {
	return d.Gw.generateToken(orgID, "")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (DefaultKeyGenerator) GenerateHMACSecret

GenerateHMACSecret is a utility function for generating new auth keys. Returns the storage key name and the actual key

func (DefaultKeyGenerator) GenerateHMACSecret() string {
	return base64.StdEncoding.EncodeToString([]byte(uuid.NewHex()))
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: base64.StdEncoding, uuid.NewHex.

func (LDAPStorageHandler) AddToSet

func (l LDAPStorageHandler) AddToSet(keyName, value string) {
	log.Error("Not implemented")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) AddToSortedSet

func (l LDAPStorageHandler) AddToSortedSet(keyName, value string, score float64) {
	log.Error("Not implemented")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) AppendToSet

func (l LDAPStorageHandler) AppendToSet(keyName, value string) {
	log.Error("Not implemented")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) DeleteScanMatch

func (l LDAPStorageHandler) DeleteScanMatch(pattern string) bool {
	log.Error("Not implemented")
	return false
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) Exists

func (l LDAPStorageHandler) Exists(keyName string) (bool, error) {
	log.Error("Not implemented")
	return false, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) GetAndDeleteSet

func (l LDAPStorageHandler) GetAndDeleteSet(keyName string) []interface{} {
	log.Error("Not implemented")
	return nil
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func (LDAPStorageHandler) GetKeyPrefix

func (l LDAPStorageHandler) GetKeyPrefix() string {
	log.Error("Not implemented")
	return ""
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) GetSet

func (l LDAPStorageHandler) GetSet(keyName string) (map[string]string, error) {
	log.Error("Not implemented")
	return nil, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) GetSortedSetRange

func (l LDAPStorageHandler) GetSortedSetRange(keyName, scoreFrom, scoreTo string) ([]string, []float64, error) {
	log.Error("Not implemented")
	return nil, nil, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) RemoveFromList

func (l LDAPStorageHandler) RemoveFromList(keyName, value string) error {
	log.Error("Not implemented")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) RemoveFromSet

func (l LDAPStorageHandler) RemoveFromSet(keyName, value string) {
	log.Error("Not implemented")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (LDAPStorageHandler) RemoveSortedSetRange

func (l LDAPStorageHandler) RemoveSortedSetRange(keyName, scoreFrom, scoreTo string) error {
	log.Error("Not implemented")
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (MethodNotAllowedHandler) ServeHTTP

func (m MethodNotAllowedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	doJSONWrite(w, http.StatusMethodNotAllowed, apiError("Method not supported"))
}

Cognitive complexity: 0, Cyclomatic complexity: 1

Uses: http.StatusMethodNotAllowed.

func (Monitor) Check

func (m Monitor) Check(sessionData *user.SessionState, key string) {
	if !m.Enabled() {
		return
	}

	if m.checkLimit(sessionData, key, sessionData.QuotaMax, sessionData.QuotaRemaining, sessionData.QuotaRenews) {
		return
	}

	for _, ac := range sessionData.AccessRights {
		if ac.Limit.IsEmpty() {
			continue
		}

		if m.checkLimit(sessionData, key, ac.Limit.QuotaMax, ac.Limit.QuotaRemaining, ac.Limit.QuotaRenews) {
			return
		}
	}
}

Cognitive complexity: 11, Cyclomatic complexity: 6

func (Monitor) Enabled

func (m Monitor) Enabled() bool {
	return m.Gw.GetConfig().Monitor.EnableTriggerMonitors
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (Monitor) Fire

func (m Monitor) Fire(sessionData *user.SessionState, key string, triggerLimit, usagePercentage float64) {
	em := config.EventMessage{
		Type:	EventTriggerExceeded,
		Meta: EventTriggerExceededMeta{
			EventMetaDefault:	EventMetaDefault{Message: "Quota trigger reached"},
			OrgID:			sessionData.OrgID,
			Key:			key,
			TriggerLimit:		int64(triggerLimit),
			UsagePercentage:	int64(usagePercentage),
		},
		TimeStamp:	time.Now().String(),
	}

	go m.Gw.MonitoringHandler.HandleEvent(em)
}

Cognitive complexity: 3, Cyclomatic complexity: 1

Uses: config.EventMessage, time.Now.

func (NotificationCommand) String

func (n NotificationCommand) String() string {
	return string(n)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (RPCStorageHandler) AddToSet

func (r RPCStorageHandler) AddToSet(keyName, value string) {
	log.Error("RPCStorageHandler.AddToSet - Not implemented")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (RPCStorageHandler) GetSet

func (r RPCStorageHandler) GetSet(keyName string) (map[string]string, error) {
	log.Error("RPCStorageHandler.GetSet - Not implemented")
	return nil, nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (RPCStorageHandler) IsRetriableError

func (r RPCStorageHandler) IsRetriableError(err error) bool {
	if err != nil {
		return err.Error() == "Access Denied"
	}
	return false
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (RPCStorageHandler) RemoveFromSet

func (r RPCStorageHandler) RemoveFromSet(keyName, value string) {
	log.Error("RPCStorageHandler.RemoveFromSet - Not implemented")
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (RedisPurger) PurgeLoop

func (r RedisPurger) PurgeLoop(ctx context.Context) {
	tick := time.NewTicker(time.Second)
	defer tick.Stop()
	for {
		select {
		case <-ctx.Done():
			return
		case <-tick.C:
			r.PurgeCache()
		}
	}
}

Cognitive complexity: 5, Cyclomatic complexity: 4

Uses: time.NewTicker, time.Second.

func (ResponseGoPluginMiddleware) Base

func (h ResponseGoPluginMiddleware) Base() *BaseTykResponseHandler {
	return &h.BaseTykResponseHandler
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (ResponseGoPluginMiddleware) Name

func (ResponseGoPluginMiddleware) Name() string {
	return "ResponseGoPluginMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (ResponseTransformJQMiddleware) Base

func (h ResponseTransformJQMiddleware) Base() *BaseTykResponseHandler {
	return &h.BaseTykResponseHandler
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (ResponseTransformJQMiddleware) Name

func (ResponseTransformJQMiddleware) Name() string {
	return "ResponseTransformJQMiddleware"
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (TraceMiddleware) ProcessRequest

func (tr TraceMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (error, int) {
	if trace.IsEnabled() {
		span, ctx := trace.Span(r.Context(),
			tr.Name(),
		)
		defer span.Finish()
		setContext(r, ctx)
		return tr.TykMiddleware.ProcessRequest(w, r, conf)
	}

	if baseMw := tr.Base(); baseMw != nil {
		cfg := baseMw.Gw.GetConfig()
		if cfg.OpenTelemetry.Enabled {
			otel.AddTraceID(r.Context(), w)
			var span otel.Span
			if baseMw.Spec.DetailedTracing {
				var ctx context.Context
				ctx, span = baseMw.Gw.TracerProvider.Tracer().Start(r.Context(), tr.Name())
				defer span.End()
				setContext(r, ctx)
			} else {
				span = otel.SpanFromContext(r.Context())
			}

			err, i := tr.TykMiddleware.ProcessRequest(w, r, conf)
			if err != nil {
				span.SetStatus(otel.SPAN_STATUS_ERROR, err.Error())
			}

			attrs := ctxGetSpanAttributes(r, tr.TykMiddleware.Name())
			if len(attrs) > 0 {
				span.SetAttributes(attrs...)
			}

			return err, i
		}
	}

	return tr.TykMiddleware.ProcessRequest(w, r, conf)
}

Cognitive complexity: 15, Cyclomatic complexity: 7

Uses: context.Context, otel.AddTraceID, otel.SPAN_STATUS_ERROR, otel.Span, otel.SpanFromContext, trace.IsEnabled, trace.Span.

func (ZipBundleSaver) Save

Save implements the main method of the BundleSaver interface. It makes use of archive/zip.

func (ZipBundleSaver) Save(bundle *Bundle, bundlePath string, spec *APISpec) error {
	buf := bytes.NewReader(bundle.Data)
	reader, err := zip.NewReader(buf, int64(len(bundle.Data)))
	if err != nil {
		return err
	}

	for _, f := range reader.File {
		destPath := filepath.Join(bundlePath, f.Name)

		if f.FileHeader.Mode().IsDir() {
			if err := os.Mkdir(destPath, 0700); err != nil {
				return err
			}
			continue
		}
		rc, err := f.Open()
		if err != nil {
			return err
		}
		newFile, err := os.Create(destPath)
		if err != nil {
			return err
		}
		if _, err = io.Copy(newFile, rc); err != nil {
			return err
		}
		rc.Close()
		if err := newFile.Close(); err != nil {
			return err
		}
	}
	return nil
}

Cognitive complexity: 17, Cyclomatic complexity: 9

Uses: bytes.NewReader, filepath.Join, io.Copy, os.Create, os.Mkdir, zip.NewReader.

func (accessTokenGen) GenerateAccessToken

GenerateAccessToken generates base64-encoded UUID access and refresh tokens

func (a accessTokenGen) GenerateAccessToken(data *osin.AccessData, generaterefresh bool) (accesstoken, refreshtoken string, err error) {
	log.Info("[OAuth] Generating new token")

	var newSession user.SessionState
	checkPolicy := true
	if data.UserData != nil {
		checkPolicy = false
		err := json.Unmarshal([]byte(data.UserData.(string)), &newSession)
		if err != nil {
			log.Info("[GenerateAccessToken] Couldn't decode user.SessionState from UserData, checking policy: ", err)
			checkPolicy = true
		}
	}

	if checkPolicy {
		// defined in JWT middleware
		sessionFromPolicy, err := a.Gw.generateSessionFromPolicy(data.Client.GetPolicyID(), "", false)
		if err != nil {
			return "", "", errors.New("Couldn't use policy or key rules to create token, failing")
		}

		newSession = sessionFromPolicy.Clone()
	}

	accesstoken = a.Gw.keyGen.GenerateAuthKey(newSession.OrgID)
	if generaterefresh {
		refreshtoken = base64.StdEncoding.EncodeToString([]byte(uuid.New()))
	}
	return
}

Cognitive complexity: 10, Cyclomatic complexity: 6

Uses: base64.StdEncoding, errors.New, json.Unmarshal, user.SessionState, uuid.New.

func (nopCloser) Close

Close is a no-op Close

func (n nopCloser) Close() error {
	return nil
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (nopCloser) Read

Read just a wrapper around real Read which also moves position to the start if we get EOF to have it ready for next read-cycle

func (n nopCloser) Read(p []byte) (int, error) {
	num, err := n.ReadSeeker.Read(p)
	if errors.Is(err, io.EOF) {	// move to start to have it ready for next read cycle
		_, seekErr := n.Seek(0, io.SeekStart)
		if seekErr != nil {
			log.WithError(seekErr).Error("can't rewind nopCloser")
		}
	}
	return num, err
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: errors.Is, io.EOF, io.SeekStart.

func (postReceiveHttpHook) Execute

func (p postReceiveHttpHook) Execute(ctx datasource.HookContext, resp *http.Response, body []byte) {
	p.m.BaseMiddleware.Logger().
		WithFields(
			logrus.Fields{
				"typename":		ctx.TypeName,
				"fieldname":		ctx.FieldName,
				"response_body":	string(body),
				"status_code":		resp.StatusCode,
			},
		).Debugf("%s.%s: postReceiveHttpHook executed", ctx.TypeName, ctx.FieldName)
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: logrus.Fields.

func (preSendHttpHook) Execute

func (p preSendHttpHook) Execute(ctx datasource.HookContext, req *http.Request) {
	p.m.BaseMiddleware.Logger().
		WithFields(
			logrus.Fields{
				"typename":	ctx.TypeName,
				"fieldname":	ctx.FieldName,
				"upstream_url":	req.URL.String(),
			},
		).Debugf("%s.%s: preSendHttpHook executed", ctx.TypeName, ctx.FieldName)
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: logrus.Fields.

func (proxy) String

func (p proxy) String() string {
	ls := ""
	if p.listener != nil {
		ls = p.listener.Addr().String()
	}
	return fmt.Sprintf("[proxy] :%d %s", p.port, ls)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

Uses: fmt.Sprintf.

func (sessionFailReason) String

func (sfr sessionFailReason) String() string {
	switch sfr {
	case sessionFailNone:
		return "sessionFailNone"
	case sessionFailRateLimit:
		return "sessionFailRateLimit"
	case sessionFailQuota:
		return "sessionFailQuota"
	default:
		return fmt.Sprintf("%d", uint(sfr))
	}
}

Cognitive complexity: 5, Cyclomatic complexity: 5

Uses: fmt.Sprintf.

Private functions

func addBodyHash

addBodyHash (req *http.Request, regex string, h hash.Hash) error
References: hex.EncodeToString, io.WriteString, murmur3.New128, regexp.Compile.

func addCustomHeader

addCustomHeader (h http.Header, key string, value []string, ignoreCanonical bool)

func addGroupsToContextData

addGroupsToContextData (cd map[string]interface{}, keyPrefix string, groups []string)
References: strconv.Itoa, strings.Join.

func addMascotHeaders

addMascotHeaders (w http.ResponseWriter)
References: fmt.Sprintf, strings.Split.

func addMatchToContextData

addMatchToContextData (cd map[string]interface{}, match []string, trNum int, trName string, indices ...int)

func addSecureAndCacheHeaders

addSecureAndCacheHeaders (next http.HandlerFunc) http.HandlerFunc
References: http.Request, http.ResponseWriter.

func addVersionHeader

addVersionHeader (w http.ResponseWriter, r *http.Request, globalConf config.Config)

func allowMethods

allowMethods (next http.HandlerFunc, methods ...string) http.HandlerFunc
References: http.Request, http.ResponseWriter, http.StatusMethodNotAllowed.

func apiError

apiError (msg string) apiStatusMessage

func apiOk

apiOk (msg string) apiStatusMessage

func appendIfMissing

appendIfMissing ensures dest slice is unique with new items.

appendIfMissing (src []string, in ...string) []string

func areMapsEqual

check if 2 maps are the same

areMapsEqual (a,b map[string]string) bool

func assertSigningMethod

assertSigningMethod asserts the provided signing method with that of jwt.

assertSigningMethod (signingMethod string, token *jwt.Token) error
References: fmt.Errorf.

func buildTriggerKey

buildTriggerKey (num int, name string, indices ...int) string
References: strconv.Itoa, strings.Join.

func bundleError

bundleError is a log helper.

bundleError (spec *APISpec, err error, message string) error
References: errors.New, fmt.Sprintf, logrus.Fields.

func cgoCString

cgoCString (in string) *_Ctype_char

func cgoCint

cgoCint (in int) _Ctype_int

func cgoGoString

cgoGoString (in *_Ctype_char) string

func checkContextTrigger

checkContextTrigger (r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool

func checkHeaderTrigger

checkHeaderTrigger (r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool
References: textproto.CanonicalMIMEHeaderKey.

func checkPathParts

checkPathParts (r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool
References: strings.Split.

func checkPayload

checkPayload (r *http.Request, options apidef.StringRegexMap, triggernum int) bool
References: bytes.NewBuffer, io.NopCloser, io.ReadAll.

func checkQueryString

checkQueryString (r *http.Request, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool

func checkSessionTrigger

checkSessionTrigger (r *http.Request, sess *user.SessionState, options map[string]apidef.StringRegexMap, any bool, triggernum int) bool

func chunkedResponseHandler

chunkedResponseHandler (w http.ResponseWriter, r *http.Request)
References: http.Flusher.

func cleanIdleMemConnProviders

cleanIdleMemConnProviders checks memconn.Provider instances periodically and deletes idle ones.

cleanIdleMemConnProviders (ctx context.Context)
References: time.NewTicker, time.Now.

func cleanIdleMemConnProvidersEagerly

cleanIdleMemConnProvidersEagerly deletes idle memconn.Provider instances and closes the underlying listener to free resources.

cleanIdleMemConnProvidersEagerly (pointInTime time.Time)

func cloneHeader

cloneHeader (h http.Header) http.Header
References: http.Header.

func compressBuffer

compressBuffer (in bytes.Buffer, encoding string) bytes.Buffer
References: flate.NewWriter, gzip.NewWriter.

func compressedResponseHandler

compressedResponseHandler (w http.ResponseWriter, r *http.Request)
References: gzip.NewWriter, json.NewEncoder.

func contains

contains checks whether the given slice contains the given item.

contains (s []string, i string) bool

func containsEscapedChars

checks if a string contains escaped characters

containsEscapedChars (str string) bool
References: url.PathUnescape.

func coprocessAuthEnabled

coprocessAuthEnabled (spec *APISpec) bool

func copyAllowedURLs

copyAllowedURLs (input []user.AccessSpec) []user.AccessSpec
References: user.AccessSpec.

func copyBody

copyBody (body io.ReadCloser, greedy bool) (io.ReadCloser, error)
References: io.SeekStart.

func copyHeader

copyHeader (dst,src http.Header, ignoreCanonical bool)

func copyRequest

copyRequest (r *http.Request) (*http.Request, error)

func copyResponse

copyResponse (r *http.Response) (*http.Response, error)
References: http.StatusSwitchingProtocols.

func countApisByListenHash

countApisByListenHash (specs []*APISpec) map[string]int
References: logrus.Fields.

func createConnectionStringFromDashboardObject

createConnectionStringFromDashboardObject (config dashboardConfigPayload) string
References: strconv.Itoa, strings.TrimRight.

func createJWKTokenHMAC

createJWKTokenHMAC (jGen ...func(*jwt.Token)) string

func createMemConnProviderIfNeeded

createMemConnProviderIfNeeded creates a new memconn.Provider and net.Listener for the given host.

createMemConnProviderIfNeeded (handler http.Handler, r *http.Request) error
References: http.HandlerFunc, http.NewServeMux, http.Request, http.ResponseWriter, http.Serve, memconn.Provider, time.Now.

func createMockReadCloserWithError

createMockReadCloserWithError (err error) *MockReadCloser

func ctxCheckLimits

Should we check Rate limits and Quotas?

ctxCheckLimits (r *http.Request) bool
References: ctx.CheckLoopLimits, httpctx.IsSelfLooping.

func ctxGetAuthToken

ctxGetAuthToken (r *http.Request) string
References: ctx.GetAuthToken.

func ctxGetCacheOptions

ctxGetCacheOptions returns a cache key if we need to cache request

ctxGetCacheOptions (r *http.Request) *cacheOptions
References: ctx.CacheOptions.

func ctxGetDefaultVersion

ctxGetDefaultVersion (r *http.Request) bool
References: ctx.VersionDefault.

func ctxGetDoNotTrack

ctxGetDoNotTrack (r *http.Request) bool
References: ctx.DoNotTrackThisEndpoint.

func ctxGetGraphQLIsWebSocketUpgrade

ctxGetGraphQLIsWebSocketUpgrade (r *http.Request) bool
References: ctx.GraphQLIsWebSocketUpgrade.

func ctxGetGraphQLRequest

ctxGetGraphQLRequest (r *http.Request) *gql.Request
References: ctx.GraphQLRequest, gql.Request.

func ctxGetGraphQLRequestV2

ctxGetGraphQLRequestV2 (r *http.Request) *gqlv2.Request
References: ctx.GraphQLRequest, gqlv2.Request.

func ctxGetOperation

ctxGetOperation (r *http.Request) *Operation
References: ctx.OASOperation.

func ctxGetOrigRequestURL

ctxGetOrigRequestURL (r *http.Request) *url.URL
References: ctx.OrigRequestURL, url.URL.

func ctxGetRequestMethod

ctxGetRequestMethod (r *http.Request) string
References: ctx.RequestMethod.

func ctxGetRequestStatus

ctxGetRequestStatus (r *http.Request) RequestStatus
References: ctx.RequestStatus.

func ctxGetSession

ctxGetSession (r *http.Request) *user.SessionState
References: ctx.GetSession.

func ctxGetSpanAttributes

ctxGetSpanAttributes (r *http.Request, mwName string) []otel.SpanAttribute
References: otel.SpanAttribute.

func ctxGetTrackedPath

ctxGetTrackedPath (r *http.Request) string
References: ctx.TrackThisEndpoint.

func ctxGetTransformRequestMethod

ctxGetTransformRequestMethod (r *http.Request) string
References: ctx.TransformedRequestMethod.

func ctxGetURLRewriteTarget

ctxGetURLRewriteTarget (r *http.Request) *url.URL
References: ctx.UrlRewriteTarget, url.URL.

func ctxGetUrlRewritePath

ctxGetUrlRewritePath (r *http.Request) string
References: ctx.UrlRewritePath.

func ctxGetVersionInfo

ctxGetVersionInfo (r *http.Request) *apidef.VersionInfo
References: apidef.VersionInfo, ctx.VersionData.

func ctxGetVersionName

ctxGetVersionName (r *http.Request) *string
References: ctx.VersionName.

func ctxIncLoopLevel

ctxIncLoopLevel (r *http.Request, loopLimit int)

func ctxIncThrottleLevel

ctxIncThrottleLevel (r *http.Request, throttleLimit int)

func ctxLoopLevel

ctxLoopLevel (r *http.Request) int
References: ctx.LoopLevel.

func ctxLoopLevelLimit

ctxLoopLevelLimit (r *http.Request) int
References: ctx.LoopLevelLimit.

func ctxLoopingEnabled

ctxLoopingEnabled (r *http.Request) bool

func ctxSetCacheOptions

ctxSetCacheOptions sets a cache key to use for the http request

ctxSetCacheOptions (r *http.Request, options *cacheOptions)
References: ctx.CacheOptions.

func ctxSetCheckLoopLimits

ctxSetCheckLoopLimits (r *http.Request, b bool)
References: ctx.CheckLoopLimits.

func ctxSetDefaultVersion

ctxSetDefaultVersion (r *http.Request)
References: ctx.VersionDefault.

func ctxSetDoNotTrack

ctxSetDoNotTrack (r *http.Request, b bool)
References: ctx.DoNotTrackThisEndpoint.

func ctxSetGraphQLIsWebSocketUpgrade

ctxSetGraphQLIsWebSocketUpgrade (r *http.Request, isWebSocketUpgrade bool)
References: ctx.GraphQLIsWebSocketUpgrade.

func ctxSetGraphQLRequest

ctxSetGraphQLRequest (r *http.Request, gqlRequest *gql.Request)
References: ctx.GraphQLRequest.

func ctxSetGraphQLRequestV2

ctxSetGraphQLRequestV2 (r *http.Request, gqlRequest *gqlv2.Request)
References: ctx.GraphQLRequest.

func ctxSetJWTContextVars

ctxSetJWTContextVars (s *APISpec, r *http.Request, token *jwt.Token)

func ctxSetLoopLevel

ctxSetLoopLevel (r *http.Request, value int)
References: ctx.LoopLevel.

func ctxSetLoopLimit

ctxSetLoopLimit (r *http.Request, limit int)
References: ctx.LoopLevelLimit.

func ctxSetOperation

ctxSetOperation (r *http.Request, op *Operation)
References: ctx.OASOperation.

func ctxSetOrigRequestURL

ctxSetOrigRequestURL (r *http.Request, url *url.URL)
References: ctx.OrigRequestURL.

func ctxSetRequestMethod

ctxSetRequestMethod (r *http.Request, path string)
References: ctx.RequestMethod.

func ctxSetRequestStatus

ctxSetRequestStatus (r *http.Request, stat RequestStatus)
References: ctx.RequestStatus.

func ctxSetSession

ctxSetSession (r *http.Request, s *user.SessionState, scheduleUpdate bool, hashKey bool)
References: ctx.SetSession.

func ctxSetSpanAttributes

ctxSetSpanAttributes (r *http.Request, mwName string, attrs ...otel.SpanAttribute)

func ctxSetThrottleLevel

ctxSetThrottleLevel (r *http.Request, value int)
References: ctx.ThrottleLevel.

func ctxSetThrottleLimit

ctxSetThrottleLimit (r *http.Request, limit int)
References: ctx.ThrottleLevelLimit.

func ctxSetTrace

ctxSetTrace (r *http.Request)
References: ctx.Trace.

func ctxSetTrackedPath

ctxSetTrackedPath (r *http.Request, p string)
References: ctx.TrackThisEndpoint.

func ctxSetTransformRequestMethod

ctxSetTransformRequestMethod (r *http.Request, path string)
References: ctx.TransformedRequestMethod.

func ctxSetURLRewriteTarget

ctxSetURLRewriteTarget (r *http.Request, url *url.URL)
References: ctx.UrlRewriteTarget.

func ctxSetUrlRewritePath

ctxSetUrlRewritePath (r *http.Request, path string)
References: ctx.UrlRewritePath.

func ctxSetVersionInfo

ctxSetVersionInfo (r *http.Request, v *apidef.VersionInfo)
References: ctx.VersionData.

func ctxSetVersionName

ctxSetVersionName (r *http.Request, vName *string)
References: ctx.VersionName.

func ctxThrottleLevel

ctxThrottleLevel (r *http.Request) int
References: ctx.ThrottleLevel.

func ctxThrottleLevelLimit

ctxThrottleLevelLimit (r *http.Request) int
References: ctx.ThrottleLevelLimit.

func ctxTraceEnabled

ctxTraceEnabled (r *http.Request) bool
References: ctx.Trace.

func dashboardServiceInit

dashboardServiceInit (gw *Gateway)

func deepCopyBody

Creates a deep copy of source request.Body and replaces target request.Body with it.

deepCopyBody (source *http.Request, target *http.Request) error
References: bytes.NewBuffer, httputil.IsStreamingRequest, io.NopCloser, io.ReadAll.

func defaultTykErrors

defaultTykErrors ()
References: config.TykError.

func doJSONExport

doJSONExport (w http.ResponseWriter, code int, obj interface{}, fileName string)
References: fmt.Sprintf, http.Error, http.StatusInternalServerError, http.StatusOK, json.MarshalIndent.

func doJSONWrite

doJSONWrite (w http.ResponseWriter, code int, obj interface{})
References: header.ApplicationJSON, header.ContentType, http.Error, http.StatusInternalServerError, http.StatusOK, json.NewEncoder, strconv.Itoa.

func dummyGetCertificate

dummyGetCertificate needed because TLSConfig require setting Certificates array or GetCertificate function from start, even if it get overridden by getTLSConfigForClient

dummyGetCertificate ( *tls.ClientHelloInfo) (*tls.Certificate, error)

func eraseSyncMap

eraseSyncMap uses native sync.Map functions to clear the map without needing to unsafely modify the value to nil.

eraseSyncMap (m *sync.Map)

func errorAndStatusCode

errorAndStatusCode (errType string) (error, int)
References: errors.New.

func estimateTagsCapacity

estimateTagsCapacity (session *user.SessionState, apiSpec *APISpec) int

func explicitRouteSubpaths

explicitRouteSubpaths (prefix string, handler http.Handler, enabled bool) http.Handler
References: strings.Contains, strings.HasSuffix.

func extractOASObjFromReq

extractOASObjFromReq (reqBody io.Reader) ([]byte, *oas.OAS, error)
References: ioutil.ReadAll, oas.OAS, openapi3.NewLoader.

func findRouteAndOperation

findRouteAndOperation (spec *APISpec, r *http.Request)

func fireEvent

fireEvent (name apidef.TykEvent, meta interface{}, handlers map[apidef.TykEvent][]config.TykEventHandler)
References: config.EventMessage, time.Now.

func firstVals

firstVals (vals map[string][]string) map[string]string

func fixFuncPath

fixFuncPath (pathPrefix string, funcs []apidef.MiddlewareDefinition)
References: filepath.Join.

func generateDomainPath

generateDomainPath (hostname,listenPath string) string

func generateGraphQLDataSource

generateGraphQLDataSource (gen ...func(graphQLDataSource *datasource.GraphQLDataSourceConfig)) json.RawMessage
References: datasource.GraphQLDataSourceConfig, datasource.TypeFieldConfiguration, json.Marshal, json.Unmarshal.

func generateGraphQLDataSourceV2

generateGraphQLDataSourceV2 (gen func(dataSource *apidef.GraphQLEngineDataSource, graphqlConf *apidef.GraphQLEngineDataSourceConfigGraphQL)) apidef.GraphQLEngineDataSource
References: apidef.GraphQLEngineDataSource, apidef.GraphQLEngineDataSourceConfigGraphQL, json.Marshal, json.Unmarshal.

func generateHMACEncodedSignature

generateHMACEncodedSignature (signatureString,secret string, algorithm string) (string, error)
References: base64.StdEncoding, errors.New, hash.Hash, hmac.New, sha1.New, sha256.New, sha512.New, sha512.New384, url.QueryEscape.

func generateHMACSignatureStringFromRequest

"Signature keyId="9876",algorithm="hmac-sha1",headers="x-test x-test-2",signature="queryEscape(base64(sig))"")

generateHMACSignatureStringFromRequest (r *http.Request, headers []string, path string) (string, error)
References: strings.ToLower, strings.TrimSpace.

func generateHeaderList

generateHeaderList (r *http.Request, headerList []string) []string
References: strings.ToLower, strings.TrimSpace, time.Now.

func generateOAuthPrefix

generateOAuthPrefix (apiID string) string

func generateRESTDataSource

generateRESTDataSource (gen ...func(restDataSource *datasource.HttpJsonDataSourceConfig)) json.RawMessage
References: datasource.HttpJsonDataSourceConfig, datasource.TypeFieldConfiguration, json.Marshal, json.Unmarshal.

func generateRESTDataSourceV2

generateRESTDataSourceV2 (gen func(dataSource *apidef.GraphQLEngineDataSource, restConf *apidef.GraphQLEngineDataSourceConfigREST)) apidef.GraphQLEngineDataSource
References: apidef.GraphQLEngineDataSource, apidef.GraphQLEngineDataSourceConfigREST, json.Marshal, json.Unmarshal.

func generateRSAEncodedSignature

generateRSAEncodedSignature (signatureString string, privateKey *rsa.PrivateKey, algorithm string) (string, error)
References: base64.StdEncoding, crypto.Hash, crypto.SHA256, cryptorand.Reader, hash.Hash, rsa.SignPKCS1v15, sha256.New.

func getAPIURL

getAPIURL (apiDef apidef.APIDefinition, gwConfig config.Config) string
References: net.JoinHostPort, strconv.Itoa, url.URL.

func getCipherAliases

getCipherAliases (ciphers []string) []uint16
References: crypto.ResolveCipher.

func getClientValidator

getClientValidator (helloInfo *tls.ClientHelloInfo, certPool *x509.CertPool) func([][]byte, [][]*x509.Certificate) error
References: errors.New, time.Now, x509.Certificate, x509.ExtKeyUsage, x509.ExtKeyUsageClientAuth, x509.NewCertPool, x509.ParseCertificate, x509.VerifyOptions.

func getDateHeader

getDateHeader (r *http.Request) (string, string)
References: logrus.Fields, strings.ToLower.

func getFieldValues

getFieldValues (authHeader string) (*HMACFieldValues, error)
References: errors.New, logrus.Fields, strconv.Unquote, strings.Split, strings.ToLower.

func getIDExtractor

getIDExtractor (spec *APISpec) IdExtractor

func getJWK

getJWK gets the JWK from URL.

getJWK (url string, jwtSSLInsecureSkipVerify bool) (*jose.JSONWebKeySet, error)
References: http.Client, http.Transport, io.ReadAll, tls.Config.

func getMapContext

getMapContext (m interface{}, k string) interface{}

func getMemConnProvider

getMemConnProvider return the cached memconn.Provider, if it's available in the cache.

getMemConnProvider (addr string) (*memconn.Provider, error)
References: fmt.Errorf, net.SplitHostPort.

func getPID

getPID () string
References: os.Getpid, strconv.Itoa.

func getSampleOASAPI

getSampleOASAPI () oas.OAS
References: oas.Info, oas.ListenPath, oas.OAS, oas.Server, oas.State, oas.Upstream, oas.XTykAPIGateway, openapi3.Info, openapi3.Paths, openapi3.T.

func getScopeFromClaim

getScopeFromClaim (claims jwt.MapClaims, scopeClaimName string) []string
References: strings.Split.

func getSessionTags

getSessionTags (session *user.SessionState) []string

func getStorageForPython

getStorageForPython (ctx context.Context) *storage.RedisCluster
References: config.Config, storage.NewConnectionHandler, storage.RedisCluster.

func getStreamingMiddleware

getStreamingMiddleware (base *BaseMiddleware) TykMiddleware

func getTagListAsString

getTagListAsString (tags []string) string
References: strings.Join.

func getUpstreamBasicAuthMw

getUpstreamBasicAuthMw (base *BaseMiddleware) TykMiddleware

func getUpstreamOAuthMw

getUpstreamOAuthMw (base *BaseMiddleware) TykMiddleware

func getUserIDFromClaim

getUserIDFromClaim parses jwt claims and get the userID from provided identityBaseField.

getUserIDFromClaim (claims jwt.MapClaims, identityBaseField string) (string, error)
References: errors.New.

func graphqlDataSourceHandler

graphqlDataSourceHandler (w http.ResponseWriter, r *http.Request)

func graphqlProxyUpstreamHandler

graphqlProxyUpstreamHandler (w http.ResponseWriter, r *http.Request)
References: graphql.Request, graphql.UnmarshalHttpRequest, http.CanonicalHeaderKey, http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, json.Unmarshal, strconv.Atoi.

func graphqlProxyUpstreamHandlerError

graphqlProxyUpstreamHandlerError (w http.ResponseWriter, r *http.Request)
References: http.StatusInternalServerError.

func greaterThanFloat64

greaterThanFloat64 checks whether first float64 value is bigger than second float64 value. -1 means infinite and the biggest value.

greaterThanFloat64 (first,second float64) bool

func greaterThanInt

greaterThanInt checks whether first int value is bigger than second int value. -1 means infinite and the biggest value.

greaterThanInt (first,second int) bool

func greaterThanInt64

greaterThanInt64 checks whether first int64 value is bigger than second int64 value. -1 means infinite and the biggest value.

greaterThanInt64 (first,second int64) bool

func handleDashboardRegistration

handleDashboardRegistration (gw *Gateway)

func handleInMemoryLoop

handleInMemoryLoop (handler http.Handler, r *http.Request) (*http.Response, error)

func handleOtelTracedResponse

handleOtelTracedResponse handles the tracing for the response middlewares when otel is enabled in the gateway

handleOtelTracedResponse (rh TykResponseHandler, rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error
References: errors.New, otel.SPAN_STATUS_ERROR, otel.Span, otel.SpanFromContext.

func handleResponse

handleResponse (rh TykResponseHandler, rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState, shouldTrace bool) error
References: trace.Span.

func handleResponseChain

handleResponseChain (chain []TykResponseHandler, rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) (bool, error)
References: trace.IsEnabled.

func init

init ()
References: openapi3.DefineStringFormatCallback, openapi3.SchemaErrorDetailsDisabled, time.DateOnly, time.Parse, time.RFC3339.

func initAuthKeyErrors

initAuthKeyErrors ()
References: config.TykError, http.StatusForbidden, http.StatusUnauthorized.

func initOauth2KeyExistsErrors

initOauth2KeyExistsErrors ()
References: config.TykError, http.StatusBadRequest, http.StatusForbidden.

func initProxy

initProxy (proto string, tlsConfig *tls.Config) *httpProxyHandler
References: http.Handler, http.HandlerFunc, http.MethodConnect, http.Request, http.ResponseWriter, http.Server, net.Listen, tls.Conn, tls.Listen.

func intersection

intersection gets intersection of the given two slices.

intersection (a []string, b []string) []string

func introspect

introspect (opts apidef.Introspection, accessToken string) (jwt.MapClaims, error)
References: fmt.Errorf, http.Post, http.StatusOK, io.ReadAll, json.Unmarshal, strings.NewReader, url.Values.

func invalidateTokens

invalidate tokens if we had a new policy

invalidateTokens (prevClient ExtendedOsinClientInterface, updatedClient OAuthClient, oauthManager OAuthManagerInterface)

func isBodyHashRequired

isBodyHashRequired (request *http.Request) bool
References: http.MethodPatch, http.MethodPost, http.MethodPut.

func isCORSPreflight

isCORSPreflight (r *http.Request) bool
References: http.MethodOptions.

func isExpired

isExpired (claims jwt.MapClaims) bool
References: time.Now, time.Unix.

func isGraphQLProxyOnly

isGraphQLProxyOnly (apiSpec *APISpec) bool
References: apidef.GraphQLExecutionModeProxyOnly, apidef.GraphQLExecutionModeSubgraph.

func isLoop

isLoop (r *http.Request) (bool, error)
References: fmt.Errorf.

func isPayloadSignatureValid

isPayloadSignatureValid (notification Notification) bool
References: base64.StdEncoding, crypto.SHA256, hex.EncodeToString, sha256.Sum256.

func isSafeMethod

isSafeMethod (method string) bool
References: http.MethodGet, http.MethodHead, http.MethodOptions.

func jsonMarshalString

jsonMarshalString (i interface{}) string
References: json.Marshal.

func jwkURLsChanged

jwkURLsChanged (a,b []apidef.JWK) bool

func listenPathLength

listenPathLength (listenPath string) int
References: strings.Contains, strings.Count, strings.Split.

func loadBundleManifest

loadBundleManifest will parse the manifest file and return the bundle parameters.

loadBundleManifest (bundle *Bundle, spec *APISpec, skipVerification bool) error
References: filepath.Join, json.NewDecoder, logrus.Fields, os.Open.

func loadKeyValues

parses v which is a string of key1=value1,,key2=value2 ... format and returns a map of key:value pairs.

loadKeyValues (v string) map[string]string
References: scanner.EOF, scanner.Scanner, strings.NewReader.

func mapScopeToPolicies

mapScopeToPolicies (mapping map[string]string, scope []string) []string

func mapStrsToIfaces

mapStrsToIfaces (m map[string]string) map[string]interface{}

func mockFromConfig

mockFromConfig (tykMockRespOp *oas.MockResponse) (int, []byte, []oas.Header)
References: http.StatusOK.

func mockFromOAS

mockFromOAS (r *http.Request, operation *openapi3.Operation, fromOASExamples *oas.FromOASExamples) (int, string, []byte, []oas.Header, error)
References: errors.New, fmt.Errorf, fmt.Sprintf, http.StatusBadRequest, http.StatusForbidden, http.StatusNotFound, json.Marshal, oas.ExampleExtractor, oas.Header, sort.Slice, strconv.Atoi, strconv.Itoa.

func needsGraphQLExecutionEngine

needsGraphQLExecutionEngine (apiSpec *APISpec) bool
References: apidef.GraphQLConfigVersion2, apidef.GraphQLConfigVersion3Preview, apidef.GraphQLExecutionModeExecutionEngine, apidef.GraphQLExecutionModeProxyOnly, apidef.GraphQLExecutionModeSubgraph, apidef.GraphQLExecutionModeSupergraph.

func nestedMapLookup

nestedMapLookup (m map[string]interface{}, ks ...string) interface{}

func newExtractor

newExtractor is called from the CP middleware for every API that specifies extractor settings.

newExtractor (referenceSpec *APISpec, mw *BaseMiddleware)
References: apidef.IDExtractorConfig, apidef.RegexExtractor, apidef.ValueExtractor, apidef.XPathExtractor, mapstructure.Decode.

func newIntrospectionCache

newIntrospectionCache (gw *Gateway) *introspectionCache
References: storage.RedisCluster.

func newNopCloserBuffer

newNopCloserBuffer creates a new instance of a *nopCloserBuffer.

newNopCloserBuffer (buf io.ReadCloser) (*nopCloserBuffer, error)

func nopCloseRequestBody

nopCloseRequestBody (r *http.Request)

func nopCloseRequestBodyErr

nopCloseRequestBodyErr (r *http.Request) error

func nopCloseResponseBody

nopCloseResponseBody (r *http.Response)

func oauthClientStorageID

oauthClientStorageID (clientID string) string

func overrideTykErrors

overrideTykErrors (gw *Gateway)

func parseForm

parseForm (r *http.Request)
References: bytes.Buffer, io.TeeReader, ioutil.NopCloser.

func parseJWK

parseJWK (buf []byte) (*jose.JSONWebKeySet, error)
References: json.Unmarshal.

func parseJWTKey

parseJWTKey parses JWT key based on signing Method

parseJWTKey (signingMethod string, secret interface{}) (interface{}, error)
References: errors.New.

func parsePoliciesFromRPC

parsePoliciesFromRPC (list string, allowExplicit bool) (map[string]user.Policy, error)
References: json.Unmarshal, user.Policy.

func proxyFromAPI

proxyFromAPI (api *APISpec) func(*http.Request) (*url.URL, error)
References: http.ProxyFromEnvironment, http.Request, url.Parse, url.URL.

func proxyTimeout

proxyTimeout (spec *APISpec) float64

func pullBundle

pullBundle (getter BundleGetter, backoffMultiplier float64) ([]byte, error)
References: backoff.NewExponentialBackOff, backoff.Retry, backoff.WithMaxRetries, time.Second.

func randStringBytes

randStringBytes (n int) string
References: mathrand.Intn.

func rawKeysWithAllowanceScope

rawKeysWithAllowanceScope (keys []string, keyName string, session *user.SessionState) []string

func readBody

readBody (req *http.Request) ([]byte, error)
References: ioutil.ReadAll.

func recordDetail

recordDetail (r *http.Request, spec *APISpec) bool
References: httputil.IsStreamingRequest.

func recordDetailUnsafe

recordDetailUnsafe (r *http.Request, spec *APISpec) bool
References: ctx.OrgSessionContext, user.SessionState.

func recordGraphDetails

recordGraphDetails (rec *analytics.AnalyticsRecord, r *http.Request, resp *http.Response, spec *APISpec)
References: apidef.GraphQLExecutionModeSubgraph, bytes.NewBuffer, graphqlinternal.NewGraphStatsExtractor, httputil.RemoveResponseTransferEncoding, io.NopCloser, io.ReadAll.

func recoverFromLoadApiPanic

recoverFromLoadApiPanic (spec *APISpec, err any) error
References: debug.Stack, fmt.Errorf.

func removeDuplicateCORSHeader

removeDuplicateCORSHeader (dst,src http.Header)
References: http.CanonicalHeaderKey.

func replaceNonAlphaNumeric

replaceNonAlphaNumeric (in string) string

func reportHealthValue

reportHealthValue is a shortcut we can use throughout the app to push a health check value

reportHealthValue (spec *APISpec, counter HealthPrefix, value string)

func requestIPHops

requestIPHops (r *http.Request) string
References: net.SplitHostPort, strings.Join.

func resetAPILimits

resetAPILimits (accessRights map[string]user.AccessDefinition)
References: user.APILimit.

func respBodyReader

respBodyReader (req *http.Request, resp *http.Response) io.ReadCloser
References: bytes.NewReader, flate.NewReader, gzip.NewReader, header.AcceptEncoding, header.ContentEncoding, ioutil.NopCloser.

func restDataSourceHandler

restDataSourceHandler (w http.ResponseWriter, r *http.Request)

func restDataSourceHandlerV2

restDataSourceHandlerV2 (w http.ResponseWriter, r *http.Request)

func restHeadersDataSourceHandler

restHeadersDataSourceHandler (w http.ResponseWriter, r *http.Request)
References: json.NewEncoder.

func roundValue

roundValue (untruncated float64) float64

func sanitizeConfig

sanitizeConfig (mc map[string]interface{}) map[string]interface{}

func sanitizeKey

sanitizeKey (b *bytes.Buffer, s string)

func saveBundle

saveBundle will save a bundle to the disk, see ZipBundleSaver methods for reference.

saveBundle (bundle *Bundle, destPath string, spec *APISpec) error

func setCustomHeader

setCustomHeader (h http.Header, key string, value string, ignoreCanonical bool)

func setCustomHeaderMultipleValues

setCustomHeaderMultipleValues accepts multiple values for a key header and append it

setCustomHeaderMultipleValues (h http.Header, key string, values []string, ignoreCanonical bool)

func shouldAddConfigData

shouldAddConfigData (spec *APISpec) bool

func shouldPerformTracing

shouldPerformTracing (rh TykResponseHandler, baseMw *BaseTykResponseHandler) bool

func shouldReloadSpec

shouldReloadSpec (existingSpec,newSpec *APISpec) bool
References: apidef.GrpcDriver, middleware.Enabled.

func shouldRewriteHost

shouldRewriteHost (oldURL,newURL *url.URL) bool

func singleJoiningSlash

singleJoiningSlash (targetPath,subPath string, disableStripSlash bool) string
References: strings.TrimLeft, strings.TrimRight.

func sortSpecsByListenPath

sortSpecsByListenPath (specs []*APISpec)
References: sort.Slice.

func specToJson

specToJson (spec *APISpec) string
References: json.Marshal.

func stripBearer

stripBearer (token string) string
References: strings.ToUpper.

func stripSignature

stripSignature (token string) string
References: strings.TrimPrefix, strings.TrimSpace.

func stripSlashes

stripSlashes removes any trailing slashes from the request's URL path.

stripSlashes (next http.Handler) http.Handler
References: http.HandlerFunc, http.Request, http.ResponseWriter, strings.TrimRight.

func subGraphAccountsHandlerAllAccounts

subGraphAccountsHandlerAllAccounts (w http.ResponseWriter, req *http.Request)

func subgraphAccountsHandler

subgraphAccountsHandler (w http.ResponseWriter, r *http.Request)

func subgraphReviewsHandler

subgraphReviewsHandler (w http.ResponseWriter, r *http.Request)

func syncHeadersAndMultiValueHeaders

syncHeadersAndMultiValueHeaders synchronizes the content of 'headers' and 'multiValueHeaders'. If a key is updated or added in 'headers', the corresponding key in 'multiValueHeaders' is also updated or added. If a key is removed from 'headers', the corresponding key in 'multiValueHeaders' is also removed. If multiValuesHeaders contains a key with multiple values and the same key is present in headers, the first value in multiValuesHeaders is updated with the value from headers, while the remaining values remain unchanged.

syncHeadersAndMultiValueHeaders (headers map[string]string, multiValueHeaders []*coprocess.Header) []*coprocess.Header
References: coprocess.Header.

func syncResourcesWithReload

syncResourcesWithReload (resource string, conf config.Config, syncFunc func() (int, error)) (int, error)
References: fmt.Errorf, time.Duration, time.Second, time.Sleep.

func tagHeaders

tagHeaders (r *http.Request, th []string, tags []string) []string
References: strings.ToLower.

func target

target (listenAddress string, listenPort int) string
References: fmt.Sprintf.

func timeValidateJWTClaims

timeValidateJWTClaims validates JWT with provided clock skew, to overcome skew occurred with distributed systems.

timeValidateJWTClaims (c jwt.MapClaims, expiresAt,issuedAt,notBefore uint64) *jwt.ValidationError
References: errors.New, time.Now.

func tlsClientConfig

tlsClientConfig (s *APISpec, gw *Gateway) *tls.Config
References: tls.Certificate, tls.Config, tls.RenegotiateFreelyAsClient, url.Parse.

func toScopeStringsSlice

toScopeStringsSlice (v interface{}, scopeSlice *[]string, nested bool) []string
References: strings.Split.

func transformBody

transformBody (r *http.Request, tmeta *TransformSpec, t *TransformMiddleware) error
References: apidef.RequestJSON, apidef.RequestXML, bytes.Buffer, bytes.NewBufferString, fmt.Errorf, io.NopCloser, ioutil.ReadAll, json.Unmarshal, mxj.NewMapXml, mxj.XmlCharsetReader.

func trimCategories

trimCategories (name string) string
References: strings.Index.

func updateOASServers

updateOASServers (spec *APISpec, conf config.Config, apiDef *apidef.APIDefinition, oasObj *oas.OAS)

func upgradeType

upgradeType (h http.Header) string
References: httpguts.HeaderValuesContainsToken, strings.ToLower.

func urlFromService

urlFromService (spec *APISpec, gw *Gateway) (*apidef.HostList, error)
References: apidef.HostList, apidef.NewHostList.

func userRatesCheck

userRatesCheck (w http.ResponseWriter, r *http.Request)
References: http.StatusBadRequest, http.StatusOK.

func valToStr

valToStr (v interface{}) string
References: reflect.TypeOf, strconv.FormatFloat, strconv.FormatInt, strings.Join, strings.TrimPrefix, url.QueryEscape, url.Values.

func validateAPIDef

validateAPIDef (apiDef *apidef.APIDefinition) *apiStatusMessage
References: apidef.DefaultValidationRuleSet, apidef.Validate, fmt.Sprintf.

func validateCommonName

validateCommonName (host string, cert *x509.Certificate) error
References: errors.New.

func validateRSAEncodedSignature

validateRSAEncodedSignature (signatureString string, publicKey *rsa.PublicKey, algorithm string, signature string) (bool, error)
References: base64.StdEncoding, crypto.Hash, crypto.SHA256, hash.Hash, rsa.VerifyPKCS1v15, sha256.New.

func writeNewConfiguration

writeNewConfiguration (payload ConfigPayload) error
References: ioutil.WriteFile, json.MarshalIndent.

func writePIDFile

writePIDFile (file string) error
References: filepath.Dir, ioutil.WriteFile, os.MkdirAll.

func writeProfiles

writeProfiles ()
References: cli.BlockProfile, cli.MutexProfile, os.Create, pprof.Lookup.

func compileTransformJQPathSpec

compileTransformJQPathSpec (paths []apidef.TransformJQMeta, stat URLStatus) []URLSpec

func getMatchPathAndMethod

getMatchPathAndMethod retrieves the match path and method from the request based on the mode.

getMatchPathAndMethod (r *http.Request, mode URLStatus) (string, string)
References: strings.HasPrefix.

func getURLStatus

getURLStatus (stat URLStatus) RequestStatus

func getVersionFromRequest

getVersionFromRequest (r *http.Request) string
References: apidef.HeaderLocation, apidef.URLLocation, apidef.URLParamLocation, regexp.Compile, strings.Replace, strings.Split, strings.TrimPrefix.

func hasVirtualEndpoint

hasVirtualEndpoint () bool

func injectIntoReqContext

injectIntoReqContext (req *http.Request)
References: ctx.SetDefinition, ctx.SetOASDefinition.

func isListeningOnPort

isListeningOnPort checks whether the API listens on the given port.

isListeningOnPort (port int, gwConfig *config.Config) bool

func isStreamingAPI

isStreamingAPI () bool
References: streams.ExtensionTykStreaming.

func setHasMock

setHasMock ()

func validateHTTP

validateHTTP () error

func validateTCP

validateTCP () error
References: errors.New.

func getAuthType

getAuthType overrides BaseMiddleware.getAuthType.

getAuthType () string
References: apidef.AuthTokenType.

func reportInvalidKey

reportInvalidKey (key string, r *http.Request, msg string, errMsg string) (error, int)

func setContextVars

setContextVars (r *http.Request, token string)

func validateSignature

validateSignature (r *http.Request, key string) (error, int)
References: errors.New, http.StatusInternalServerError, http.StatusOK, signaturevalidator.SignatureValidator.

func emitRateLimitEvent

emitRateLimitEvent emits a specific rate limit event with an optional custom message.

emitRateLimitEvent (r *http.Request, e event.Event, message string, rateLimitKey string)
References: event.String, request.RealIP.

func emitRateLimitEvents

emitRateLimitEvents emits rate limit related events based on the request context.

emitRateLimitEvents (r *http.Request, rateLimitKey string)
References: event.Get, event.RateLimitSmoothingDown, event.RateLimitSmoothingUp.

func generateSessionID

generateSessionID (id string) string
References: fmt.Sprintf, md5.Sum.

func getAuthToken

getAuthToken (authType string, r *http.Request) (string, apidef.AuthConfig)
References: apidef.AuthTokenType, apidef.JWTType, header.Authorization.

func getAuthType

getAuthType () string

func handleRateLimitFailure

handleRateLimitFailure handles the actions to be taken when a rate limit failure occurs.

handleRateLimitFailure (r *http.Request, e event.Event, message string, rateLimitKey string) (error, int)
References: errors.New, http.StatusTooManyRequests.

func basicAuthBodyCredentials

basicAuthBodyCredentials (w http.ResponseWriter, r *http.Request) (string, error, int)
References: bytes.NewReader, errors.New, http.StatusBadRequest, ioutil.NopCloser, ioutil.ReadAll.

func basicAuthHeaderCredentials

basicAuthHeaderCredentials (w http.ResponseWriter, r *http.Request) (string, error, int)
References: base64.StdEncoding, errors.New, http.StatusBadRequest, strings.Split.

func checkPassword

checkPassword (session *user.SessionState, plainPassword string, logger *logrus.Entry) error
References: storage.HashStr, user.HashBCrypt, user.HashMurmur128, user.HashMurmur32, user.HashMurmur64, user.HashPlainText, user.HashSha256.

func compareHashAndPassword

compareHashAndPassword (hash string, password string, logEntry *logrus.Entry) error
References: bcrypt.CompareHashAndPassword, murmur3.New64.

func doBcryptWithCache

doBcryptWithCache (cacheDuration int64, hashedPassword []byte, password []byte) error
References: bcrypt.CompareHashAndPassword, murmur3.New64.

func getAuthType

getAuthType overrides BaseMiddleware.getAuthType.

getAuthType () string
References: apidef.BasicType.

func handleAuthFail

handleAuthFail (w http.ResponseWriter, r *http.Request, token string) (error, int)

func requestForBasicAuth

requestForBasicAuth sends error code and message along with WWW-Authenticate header to client.

requestForBasicAuth (w http.ResponseWriter, msg string) (error, int)
References: errors.New, header.WWWAuthenticate, http.StatusUnauthorized.

func doRequest

doRequest will make the same request but return a BatchReplyUnit

doRequest (req *http.Request, relURL string) BatchReplyUnit
References: http.Client, http.Transport, ioutil.ReadAll, tls.Certificate, tls.Config.

func getAuthType

getAuthType overrides BaseMiddleware.getAuthType.

getAuthType () string
References: apidef.CoprocessType.

func getAvgCount

getAvgCount (prefix HealthPrefix) float64

func clearCacheForKey

clearCacheForKey (keyName string, hashed bool)
References: storage.HashKey.

func deleteRawKeysWithAllowanceScope

deleteRawKeysWithAllowanceScope (store storage.Handler, session *user.SessionState, keyName string)

func generateVirtualSessionFor

generateVirtualSessionFor generates a virtual session for the given access token by using its identifier.

generateVirtualSessionFor (r *http.Request, sessionID string) user.SessionState
References: user.APILimit, user.AccessDefinition.

func getAuthType

getAuthType overrides BaseMiddleware.getAuthType.

getAuthType () string
References: apidef.ExternalOAuthType.

func getSecretFromJWKOrConfig

getSecretFromJWKOrConfig gets the secret to verify jwt signature from API definition or from JWK set if config is set to a URL

getSecretFromJWKOrConfig (kid interface{}, jwtValidation apidef.JWTValidation) (interface{}, error)
References: base64.StdEncoding.

func getSecretFromJWKURL

getSecretFromJWKURL gets the secret to verify jwt signature from a JWK URL.

getSecretFromJWKURL (url string, kid interface{}) (interface{}, error)
References: cache.DefaultExpiration.

func introspection

introspection makes an introspection request to third-party provider to check whether the access token is valid or not. The access token can be both JWT and opaque type.

introspection (accessToken string) (bool, string, error)
References: errors.New, fmt.Errorf.

func jwt

jwt makes access token validation without making a network call and validates access token locally. The access token should be JWT type.

jwt (accessToken string) (bool, string, error)
References: errors.New, fmt.Errorf.

func addBatchEndpoint

addBatchEndpoint (spec *APISpec, subrouter *mux.Router)

func addOAuthHandlers

Create API-specific OAuth handlers and respective auth servers

addOAuthHandlers (spec *APISpec, muxer *mux.Router) *OAuthManager
References: http.StatusForbidden, osin.NewServerConfig, storage.RedisCluster.

func addPubSubDelay

addPubSubDelay sleeps for duration

addPubSubDelay (dur time.Duration)
References: time.Sleep.

func afterConfSetup

afterConfSetup takes care of non-sensical config values (such as zero timeouts) and sets up a few globals that depend on the config.

afterConfSetup ()
References: config.DefaultOTelResourceName, regexp.ResetCache, rpc.GlobalRPCCallTimeout, rpc.GlobalRPCPingTimeout, time.Duration, time.Second.

func allApisAreMTLS

allApisAreMTLS () bool

func apiHandler

apiHandler (w http.ResponseWriter, r *http.Request)
References: afero.NewOsFs, apidef.APIDefinition, apidef.HeaderBaseAPIID, http.MethodDelete, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusBadRequest, mux.Vars.

func apiOASExportHandler

apiOASExportHandler (w http.ResponseWriter, r *http.Request)
References: fmt.Sprintf, mux.Vars.

func apiOASGetHandler

apiOASGetHandler (w http.ResponseWriter, r *http.Request)
References: apidef.HeaderBaseAPIID, mux.Vars, oas.OAS.

func apiOASPatchHandler

apiOASPatchHandler (w http.ResponseWriter, r *http.Request)
References: afero.NewOsFs, apidef.ErrAPINotFound, apidef.ErrAPINotMigrated, bytes.NewReader, http.StatusBadRequest, http.StatusInternalServerError, http.StatusNotFound, ioutil.NopCloser, mux.Vars, oas.GetTykExtensionConfigParams, oas.OAS, oas.RetainOldServerURL, oas.XTykAPIGateway, strings.TrimSpace.

func apiOASPostHandler

apiOASPostHandler (w http.ResponseWriter, r *http.Request)
References: afero.NewOsFs.

func apiOASPutHandler

apiOASPutHandler (w http.ResponseWriter, r *http.Request)
References: afero.NewOsFs, http.StatusBadRequest, mux.Vars.

func apisByIDLen

apisByIDLen () int

func applyPoliciesAndSave

applyPoliciesAndSave (keyName string, session *user.SessionState, spec *APISpec, isHashed bool) error

func backupConfiguration

backupConfiguration () error
References: ioutil.WriteFile, json.MarshalIndent, time.Now.

func basicAuthHashAlgo

basicAuthHashAlgo () string
References: user.HashBCrypt, user.IsHashType.

func blockInDashboardMode

blockInDashboardMode (next http.HandlerFunc) http.HandlerFunc
References: http.Request, http.ResponseWriter, http.StatusInternalServerError.

func buildDashboardConnStr

buildDashboardConnStr (resource string) string
References: time.Second, time.Sleep.

func cacheClose

cacheClose will close the caches in *Gateway, cleaning up the goroutines.

cacheClose ()

func cacheCreate

cacheCreate will create the caches in *Gateway.

cacheCreate ()
References: cache.New.

func certHandler

certHandler (w http.ResponseWriter, r *http.Request)
References: certs.CertificateAny, certs.CertificateBasics, certs.CertificateMeta, certs.ExtractCertificateBasics, certs.ExtractCertificateMeta, http.StatusForbidden, http.StatusNotFound, http.StatusOK, ioutil.ReadAll, mux.Vars, sha256.Size, strings.Split.

func checkAndApplyTrialPeriod

checkAndApplyTrialPeriod (keyName string, newSession *user.SessionState, isHashed bool)
References: time.Now.

func checkIsAPIOwner

checkIsAPIOwner will ensure that the accessor of the tyk API has the correct security credentials - this is a shared secret between the client and the owner and is set in the tyk.conf file. This should never be made public!

checkIsAPIOwner (next http.Handler) http.Handler
References: header.XTykAuthorization, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusForbidden.

func configureAuthAndOrgStores

configureAuthAndOrgStores (gs *generalStores, spec *APISpec) (storage.Handler, storage.Handler, storage.Handler)

func controlAPICheckClientCertificate

controlAPICheckClientCertificate (certLevel string, next http.Handler) http.Handler
References: certs.CertificatePublic, crypto.ValidateRequestCerts, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusForbidden.

func createDynamicMiddleware

createDynamicMiddleware (name string, isPre,useSession bool, baseMid *BaseMiddleware) func(http.Handler) http.Handler

func createKeyHandler

createKeyHandler (w http.ResponseWriter, r *http.Request)
References: http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, json.NewDecoder, logrus.Fields, storage.HashKey, strconv.Itoa, time.Now, user.SessionState.

func createMiddleware

Generic middleware caller to make extension easier

createMiddleware (actualMW TykMiddleware) func(http.Handler) http.Handler
References: health.Kvs, http.Handler, http.HandlerFunc, http.Request, http.ResponseWriter, newrelic.FromContext, request.RealIP, strconv.Itoa, time.Now, time.Since.

func createOauthClient

createOauthClient (w http.ResponseWriter, r *http.Request)
References: http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, json.NewDecoder, logrus.Fields, osin.ServerConfig, storage.RedisCluster, uuid.NewHex.

func createResponseMiddlewareChain

Create the response processor chain

createResponseMiddlewareChain (spec *APISpec, responseFuncs []apidef.MiddlewareDefinition)
References: storage.RedisCluster, strings.HasSuffix.

func customDialTLSCheck

customDialTLSCheck (spec *APISpec, tc *tls.Config) func(network, addr string) (net.Conn, error)
References: errors.New, net.Conn, net.SplitHostPort, tls.Dial.

func determineHealthStatus

determineHealthStatus (failCount int, criticalFailure bool, totalChecks int) (HealthCheckStatus, int)
References: http.StatusOK, http.StatusServiceUnavailable.

func dialWithServiceDiscovery

dialWithServiceDiscovery (spec *APISpec, dial dialFn) dialFn
References: net.Conn, url.Parse.

func doAddOrUpdate

doAddOrUpdate (keyName string, newSession *user.SessionState, dontReset bool, isHashed bool) error
References: errors.New, logrus.Fields, strconv.Itoa, time.Now.

func evaluateHealthChecks

evaluateHealthChecks (checks map[string]HealthCheckItem) (int, bool)

func findInternalHttpHandlerByNameOrID

findInternalHttpHandlerByNameOrID (apiNameOrID string) (http.Handler, *APISpec, bool)

func flushNetworkAnalytics

flushNetworkAnalytics (ctx context.Context)
References: analytics.AnalyticsRecord, time.NewTicker, time.Second.

func forceResponse

forceResponse (w http.ResponseWriter, r *http.Request, newResponseData *VMResponseObject, spec *APISpec, session *user.SessionState, isPre bool, logger *logrus.Entry) *http.Response
References: bytes.NewReader, http.Response, http.TimeFormat, strings.HasPrefix, time.Now, url.Parse.

func fuzzyFindAPI

fuzzyFindAPI (search string) *APISpec
References: strings.EqualFold.

func gatherHealthChecks

gatherHealthChecks ()
References: errors.New, rpc.Login, storage.RedisCluster, sync.WaitGroup, time.Now, time.RFC3339.

func generateSessionFromPolicy

generateSessionFromPolicy (policyID,orgID string, enforceOrg bool) (user.SessionState, error)
References: errors.New, time.Now, user.AccessDefinition, user.SessionState.

func generateSubRoutes

generateSubRoutes (spec *APISpec, router *mux.Router, logger *logrus.Entry)
References: cors.New, cors.Options.

func generateToken

generateToken (orgID,keyID string, customHashKeyFunction ...string) string
References: logrus.Fields, storage.GenerateToken, strings.TrimPrefix.

func getAPIDefinition

getAPIDefinition (apiID string) (*apidef.APIDefinition, error)
References: errors.New.

func getApiClients

getApiClients (apiID string) ([]ExtendedOsinClientInterface, apiStatusMessage, int)
References: http.StatusNotFound, http.StatusOK, logrus.Fields.

func getApiSpec

getApiSpec (apiID string) *APISpec

func getApisForOauthApp

getApisForOauthApp (w http.ResponseWriter, r *http.Request)
References: http.StatusOK, mux.Vars.

func getApisForOauthClientId

getApisForOauthClientId (oauthClientId string, orgId string) []string
References: http.StatusOK.

func getApisIdsForOrg

getApisIdsForOrg (orgID string) []string

func getBundleDestPath

getBundleDestPath (spec *APISpec) string
References: filepath.Join.

func getExistingConfig

getExistingConfig () (map[string]interface{}, error)
References: json.NewDecoder, os.Open.

func getExplicitLogEntryForRequest

getExplicitLogEntryForRequest (logger *logrus.Entry, path string, IP string, key string, data map[string]interface{}) *logrus.Entry
References: logrus.Fields.

func getGlobalMDCBStorageHandler

getGlobalMDCBStorageHandler (keyPrefix string, hashKeys bool) storage.Handler
References: logrus.Fields, logrus.New, storage.NewMdcbStorage, storage.RedisCluster.

func getGlobalStorageHandler

getGlobalStorageHandler (keyPrefix string, hashKeys bool) storage.Handler
References: storage.RedisCluster.

func getHashedBundleName

getHashedBundleName (bundleName string) (string, error)
References: fmt.Sprintf, io.WriteString, md5.New.

func getHealthCheckInfo

getHealthCheckInfo () map[string]HealthCheckItem

func getHostDetails

getHostDetails ()
References: os.Getpid, os.Hostname.

func getLogEntryForRequest

getLogEntryForRequest (logger *logrus.Entry, r *http.Request, key string, data map[string]interface{}) *logrus.Entry
References: logrus.Fields, logrus.NewEntry, request.RealIP.

func getOauthClientDetails

Get client details

getOauthClientDetails (keyName,apiID string) (interface{}, int)
References: http.StatusNotFound, http.StatusOK, logrus.Fields, osin.ServerConfig, storage.RedisCluster.

func getOauthClients

List Clients

getOauthClients (apiID string) (interface{}, int)
References: http.StatusOK, logrus.Fields.

func getPinnedPublicKeys

getPinnedPublicKeys (host string, spec *APISpec, conf config.Config) []string
References: strings.Split, strings.SplitN.

func getSessionAndCreate

getSessionAndCreate (keyName string, r *RPCStorageHandler, isHashed bool, orgId string)
References: storage.HashKey.

func getSpecForOrg

getSpecForOrg (orgID string) *APISpec

func getTLSConfigForClient

getTLSConfigForClient (baseConfig *tls.Config, listenPort int) func(hello *tls.ClientHelloInfo) (*tls.Config, error)
References: apidef.AuthTokenType, cache.DefaultExpiration, certs.CertificatePrivate, certs.CertificatePublic, crypto.IsPublicKey, http.Request, mux.NewRouter, mux.RouteMatch, strconv.Itoa, sync.Once, time.Millisecond, time.Sleep, tls.Certificate, tls.ClientAuthType, tls.ClientHelloInfo, tls.Config, tls.LoadX509KeyPair, tls.NoClientCert, tls.RequestClientCert, tls.RequireAndVerifyClientCert, url.URL, x509.NewCertPool.

func getTagHash

getTagHash () string

func getUpstreamCertificate

getUpstreamCertificate (host string, spec *APISpec) *tls.Certificate
References: certs.CertificatePrivate, strings.SplitN.

func gracefulShutdown

gracefulShutdown performs a graceful shutdown of all services

gracefulShutdown (ctx context.Context) error
References: fmt.Errorf, http.Server, sync.WaitGroup.

func groupResetHandler

groupResetHandler (w http.ResponseWriter, r *http.Request)
References: http.StatusOK, logrus.Fields.

func grpcCallOpts

grpcCallOpts () grpc.DialOption
References: grpc.CallOption, grpc.MaxCallRecvMsgSize, grpc.MaxCallSendMsgSize, grpc.WithDefaultCallOptions.

func handleAddApi

handleAddApi (r *http.Request, fs afero.Fs, oasEndpoint bool) (interface{}, int)
References: apidef.APIDefinition, apidef.DefaultAPIVersionKey, apidef.HeaderLocation, apidef.Self, http.StatusBadRequest, http.StatusOK, json.Marshal, json.NewDecoder, json.Unmarshal, oas.OAS.

func handleAddKey

handleAddKey (keyName,sessionString,orgId string)
References: json.Unmarshal, logrus.Fields, strconv.Itoa, time.Now, user.SessionState.

func handleAddOrUpdate

handleAddOrUpdate (keyName string, r *http.Request, isHashed bool) (interface{}, int)
References: bytes.NewReader, http.MethodPost, http.MethodPut, http.StatusBadRequest, http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, ioutil.NopCloser, ioutil.ReadAll, json.Unmarshal, storage.HashKey, storage.TokenOrg, time.Now, time.Unix, user.SessionState.

func handleAddOrUpdatePolicy

handleAddOrUpdatePolicy (polID string, r *http.Request) (interface{}, int)
References: filepath.Join, http.MethodPost, http.MethodPut, http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, ioutil.WriteFile, json.MarshalIndent, json.NewDecoder, user.Policy.

func handleDashboardZeroConfMessage

handleDashboardZeroConfMessage (payload string)
References: json.Unmarshal.

func handleDeleteAPI

handleDeleteAPI (apiID string) (interface{}, int)
References: afero.NewOsFs, apidef.ErrAPINotFound, filepath.Clean, filepath.Join, http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, json.Marshal, json.Unmarshal, os.Remove, os.Stat.

func handleDeleteHashedKey

handleDeleteHashedKey (keyName,orgID,apiID string, resetQuota bool) (interface{}, int)
References: http.StatusBadRequest, http.StatusNotFound, http.StatusOK.

func handleDeleteHashedKeyWithLogs

handleDeleteHashedKeyWithLogs is a wrapper for handleDeleteHashedKey with logs

handleDeleteHashedKeyWithLogs (keyName,orgID,apiID string, resetQuota bool) (interface{}, int)
References: http.StatusOK, logrus.Fields.

func handleDeleteKey

handleDeleteKey (keyName,orgID,apiID string, resetQuota bool) (interface{}, int)
References: http.StatusBadRequest, http.StatusNotFound, http.StatusOK, logrus.Fields.

func handleDeleteOAuthClient

Delete Client

handleDeleteOAuthClient (keyName,apiID string) (interface{}, int)
References: http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, logrus.Fields.

func handleDeleteOrgKey

handleDeleteOrgKey (orgID string) (interface{}, int)
References: http.StatusBadRequest, http.StatusNotFound, http.StatusOK, logrus.Fields.

func handleDeletePolicy

handleDeletePolicy (polID string) (interface{}, int)
References: filepath.Join, http.StatusInternalServerError, http.StatusOK, os.Remove, os.Stat.

func handleForcedResponse

handleForcedResponse (rw http.ResponseWriter, res *http.Response, ses *user.SessionState, spec *APISpec)
References: header.XRateLimitLimit, header.XRateLimitRemaining, header.XRateLimitReset, io.Copy, strconv.Itoa.

func handleGetAPI

handleGetAPI (apiID string, oasEndpoint bool) (interface{}, int)
References: apidef.ErrAPINotFound, apidef.ErrOASGetForOldAPI, fmt.Sprintf, http.StatusBadRequest, http.StatusNotFound, http.StatusOK, logrus.Fields.

func handleGetAPIList

handleGetAPIList () (interface{}, int)
References: apidef.APIDefinition, http.StatusOK.

func handleGetAPIListOAS

handleGetAPIListOAS (modePublic bool) (interface{}, int)
References: http.StatusOK, oas.OAS.

func handleGetAPIOAS

handleGetAPIOAS (apiID string, modePublic bool) (interface{}, int)
References: oas.OAS.

func handleGetAllKeys

handleGetAllKeys (filter string) (interface{}, int)
References: base64.NoPadding, base64.StdEncoding, fmt.Sprintf, http.StatusOK, logrus.Fields, strings.HasPrefix.

func handleGetAllOrgKeys

handleGetAllOrgKeys (filter string) (interface{}, int)
References: http.StatusNotFound, http.StatusOK, strings.HasPrefix.

func handleGetDetail

handleGetDetail (sessionKey,apiID,orgID string, byHash bool) (interface{}, int)
References: errors.Is, http.StatusBadRequest, http.StatusNotFound, http.StatusOK, logrus.Fields, redis.Nil, storage.HashKey, storage.TokenOrg, strconv.Atoi.

func handleGetOrgDetail

handleGetOrgDetail (orgID string) (interface{}, int)
References: http.StatusNotFound, http.StatusOK, logrus.Fields.

func handleGetPolicy

handleGetPolicy (polID string) (interface{}, int)
References: http.StatusNotFound, http.StatusOK, logrus.Fields.

func handleGetPolicyList

handleGetPolicyList () (interface{}, int)
References: http.StatusOK, user.Policy.

func handleGetSortedSetRange

handleGetSortedSetRange (keyName,scoreFrom,scoreTo string) ([]string, []float64, error)

func handleGlobalAddToSortedSet

handleGlobalAddToSortedSet (keyName,value string, score float64)

func handleKeySpaceEventCacheFlush

handleKeySpaceEventCacheFlush (payload string)
References: strings.Split.

func handleNewConfiguration

handleNewConfiguration (payload string)
References: config.Load, json.Unmarshal, logrus.Fields, syscall.Kill, syscall.SIGUSR2.

func handleOrgAddOrUpdate

handleOrgAddOrUpdate (orgID string, r *http.Request) (interface{}, int)
References: http.MethodPost, http.StatusBadRequest, http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, json.NewDecoder, logrus.Fields, storage.HashKey, strconv.Itoa, time.Now, user.SessionState.

func handleRedisEvent

handleRedisEvent (v interface{}, handled func(NotificationCommand), reloaded func())
References: json.Unmarshal, temporalmodel.Message, temporalmodel.MessageTypeMessage.

func handleRemoveSortedSetRange

handleRemoveSortedSetRange (keyName,scoreFrom,scoreTo string) error

func handleSendMiniConfig

handleSendMiniConfig (payload string)
References: json.Marshal, json.Unmarshal, logrus.Fields, time.Now.

func handleUpdateApi

handleUpdateApi (apiID string, r *http.Request, fs afero.Fs, oasEndpoint bool) (interface{}, int)
References: apidef.APIDefinition, apidef.ErrAPINotFound, apidef.ErrAPINotMigrated, apidef.ErrClassicAPIExpected, http.StatusBadRequest, http.StatusNotFound, http.StatusOK, json.NewDecoder, oas.OAS.

func handleUpdateHashedKey

handleUpdateHashedKey (keyName string, applyPolicies []string) (interface{}, int)
References: http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, logrus.Fields, strconv.Itoa, time.Now.

func handleUserKeyReset

handleUserKeyReset processes a user key reset notification

handleUserKeyReset (payload string)
References: strings.Split.

func healthCheckhandler

healthCheckhandler (w http.ResponseWriter, r *http.Request)
References: http.StatusBadRequest, http.StatusNotFound, http.StatusOK.

func initGenericEventHandlers

initGenericEventHandlers ()
References: apidef.TykEvent, config.TykEventHandler.

func initHealthCheck

initHealthCheck (ctx context.Context)
References: context.Context, logrus.Fields, time.NewTicker, time.Second.

func initNormalisationPatterns

initNormalisationPatterns () config.NormaliseURLPatterns
References: regexp.Compile, regexp.MustCompile.

func initSystem

initSystem () error
References: cli.Conf, cli.DebugMode, cli.Port, config.Config, config.DefaultDashPolicyRecordName, config.DefaultDashPolicySource, config.Global, config.Load, context.Background, context.WithTimeout, gorpc.SetErrorLogger, ioutil.Discard, logger.NewFormatter, logrus.DebugLevel, logrus.ErrorLevel, logrus.WarnLevel, os.Getenv, rpc.Instrument, rpc.Log, stdlog.SetOutput, strconv.Atoi, strings.ToLower, time.Second, tls.VersionTLS12.

func initialiseClient

initialiseClient () *http.Client
References: http.Client, http.Transport, time.Duration, time.Second, tls.Config.

func invalidateAPICache

invalidateAPICache (apiID string) bool
References: fmt.Sprintf, storage.RedisCluster.

func invalidateCacheHandler

invalidateCacheHandler (w http.ResponseWriter, r *http.Request)
References: errors.New, http.StatusInternalServerError, http.StatusOK, logrus.Fields, mux.Vars.

func invalidateOauthRefresh

invalidateOauthRefresh (w http.ResponseWriter, r *http.Request)
References: http.StatusBadRequest, http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, logrus.Fields, mux.Vars.

func isCriticalFailure

isCriticalFailure (component string) bool

func isRPCMode

isRPCMode () bool

func isRunningTests

isRunningTests () bool

func keyHandler

keyHandler (w http.ResponseWriter, r *http.Request)
References: http.MethodDelete, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusNotFound, http.StatusOK, mux.Vars.

func kvStore

kvStore (value string) (string, error)
References: fmt.Errorf, fmt.Sprintf, os.Getenv, strings.HasPrefix, strings.ToUpper, strings.TrimPrefix.

func liveCheckHandler

liveCheckHandler (w http.ResponseWriter, r *http.Request)
References: fmt.Sprintf, header.ApplicationJSON, http.MethodGet, http.StatusMethodNotAllowed, http.StatusText, json.NewEncoder.

func loadApps

Create the individual API (app) specs based on live configurations and assign middleware

loadApps (specs []*APISpec)
References: http.HandlerFunc, mux.NewRouter, sync.Map, trace.AddTracer, trace.IsEnabled.

func loadBundle

loadBundle wraps the load and save steps, it will return if an error occurs at any point.

loadBundle (spec *APISpec) error
References: logrus.Fields, os.MkdirAll, os.RemoveAll, os.Stat.

func loadControlAPIEndpoints

loadControlAPIEndpoints loads the endpoints used for controlling the Gateway.

loadControlAPIEndpoints (muxer *mux.Router)
References: cli.HTTPProfile, http.MethodDelete, http.MethodGet, http.MethodPatch, http.MethodPost, http.MethodPut, http.StripPrefix, mux.NewRouter, pprofhttp.Index, pprofhttp.Profile.

func loadCustomMiddleware

loadCustomMiddleware (spec *APISpec) ([]string, apidef.MiddlewareDefinition, []apidef.MiddlewareDefinition, []apidef.MiddlewareDefinition, []apidef.MiddlewareDefinition, []apidef.MiddlewareDefinition, apidef.MiddlewareDriver)
References: apidef.MiddlewareDefinition, apidef.MiddlewareDriver, filepath.Base, filepath.Glob, filepath.Join, strings.HasSuffix, strings.Split.

func loadGlobalApps

loadGlobalApps ()

func loadGraphQLPlayground

loadGraphQLPlayground (spec *APISpec, subrouter *mux.Router)
References: fmt.Sprintf, http.MethodGet, http.Request, http.ResponseWriter, http.StatusInternalServerError, path.Join.

func loadHTTPService

loadHTTPService has two responsibilities:

  • register gorilla/mux routing handless with proxyMux directly (wrapped),
  • return a raw http.Handler for tyk://ID urls.

loadHTTPService (spec *APISpec, apisByListen map[string]int, gs *generalStores, muxer *proxyMux) (*ChainObject, error)
References: fmt.Errorf, httputil.ValidatePath, logrus.NewEntry, mux.NewRouter, newrelic.Mount.

func loadTCPService

loadTCPService (spec *APISpec, gs *generalStores, muxer *proxyMux)

func logPubSubError

isPubSubError returns true if err != nil, logs error

logPubSubError (err error, message string) bool

func makeImportedOASTykAPI

makeImportedOASTykAPI (next http.HandlerFunc) http.HandlerFunc
References: bytes.NewReader, http.Request, http.ResponseWriter, http.StatusBadRequest, ioutil.NopCloser, oas.GetTykExtensionConfigParams, oas.TykExtensionConfigParams.

func mwAppendEnabled

mwAppendEnabled (chain *[]alice.Constructor, mw TykMiddleware) bool

func mwList

mwList (mws ...TykMiddleware) []alice.Constructor
References: alice.Constructor.

func newRedisHook

newRedisHook () *redisChannelHook
References: logrus.JSONFormatter, storage.RedisCluster.

func nextTarget

nextTarget (targetData *apidef.HostList, spec *APISpec) (string, error)
References: fmt.Errorf.

func oAuthClientHandler

oAuthClientHandler (w http.ResponseWriter, r *http.Request)
References: http.MethodDelete, http.MethodGet, http.MethodPut, mux.Vars.

func oAuthClientTokensHandler

oAuthClientTokensHandler (w http.ResponseWriter, r *http.Request)
References: http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, logrus.Fields, mux.Vars, strconv.Atoi.

func oAuthTokensHandler

oAuthTokensHandler (w http.ResponseWriter, r *http.Request)
References: http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, http.StatusUnprocessableEntity.

func obfuscateKey

obfuscateKey (keyName string) string

func onServerStatusReceivedHandler

onServerStatusReceivedHandler (payload string)
References: drl.Server, json.Unmarshal, logrus.Fields.

func orgHandler

orgHandler (w http.ResponseWriter, r *http.Request)
References: mux.Vars.

func polHandler

polHandler (w http.ResponseWriter, r *http.Request)
References: http.MethodDelete, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusBadRequest, mux.Vars.

func policyUpdateHandler

policyUpdateHandler (w http.ResponseWriter, r *http.Request)
References: http.StatusBadRequest, json.NewDecoder, mux.Vars.

func populateHostListByApiSpec

populateHostListByApiSpec (hostList *[]HostData, spec *APISpec)
References: logrus.Fields.

func preLoadVirtualMetaCode

preLoadVirtualMetaCode (meta *apidef.VirtualMeta, j *JSVM)
References: apidef.UseBlob, apidef.UseFile, base64.StdEncoding, os.Open.

func prepareStorage

prepareStorage () generalStores
References: storage.RedisCluster.

func previewKeyHandler

previewKeyHandler (w http.ResponseWriter, r *http.Request)
References: http.StatusInternalServerError, http.StatusOK, json.NewDecoder, logrus.Fields, strconv.Itoa, time.Now, user.SessionState.

func processSpec

processSpec (spec *APISpec, apisByListen map[string]int, gs *generalStores, logger *logrus.Entry) *ChainObject
References: alice.Constructor, alice.New, apidef.GoPluginDriver, apidef.MiddlewareDefinition, apidef.MiddlewareDriver, apidef.NewHostListFromList, apidef.OttoDriver, coprocess.HookType_CustomKeyCheck, coprocess.HookType_Post, coprocess.HookType_PostKeyAuth, coprocess.HookType_Pre, filepath.Join, http.Handler, http.HandlerFunc, logrus.Fields, otel.ApidefSpanAttributes, otel.HTTPHandler, otel.SpanAttribute, path.Join, rpc.IsEmergencyMode, storage.RedisCluster, strings.ToLower, tls.VersionTLS12, trace.Handle, trace.IsEnabled, url.Parse.

func purgeLapsedOAuthTokens

purgeLapsedOAuthTokens () error
References: internalerrors.Formatter, multierror.Append, multierror.Error, storage.RedisCluster, strconv.FormatInt, sync.WaitGroup, time.Minute, time.Now.

func reLogin

reLogin ()
References: time.Second, time.Sleep.

func readGraphqlPlaygroundTemplate

readGraphqlPlaygroundTemplate ()
References: filepath.Join, ioutil.ReadDir, logrus.Fields, texttemplate.ParseFiles.

func readinessHandler

readinessHandler is a dedicated endpoint for readiness probes It checks if the gateway is ready to serve requests by verifying:

  • Redis connection status
  • API definitions loaded successfully Unlike liveCheckHandler which always returns 200 OK, readinessHandler returns 503 Service Unavailable if the gateway is not ready to serve requests

readinessHandler (w http.ResponseWriter, r *http.Request)
References: header.ApplicationJSON, http.MethodGet, http.StatusMethodNotAllowed, http.StatusOK, http.StatusServiceUnavailable, http.StatusText, json.NewEncoder.

func recordTCPHit

nolint

recordTCPHit (specID string, doNotTrack bool) func(tcp.Stat)
References: atomic.AddInt64, tcp.Closed, tcp.Open, tcp.Stat.

func reloadLoop

reloadLoop (tick <-chan time.Time, complete ...func())
References: time.Now, time.Since.

func reloadQueueLoop

reloadQueueLoop (cb ...func())

func reloadURLStructure

reloadURLStructure will queue an API reload. The reload will eventually create a new muxer, reload all the app configs for an instance and then replace the DefaultServeMux with the new one. This enables a reconfiguration to take place without stopping any requests from being handled.

done will be called when the reload is finished. Note that if a reload is already queued, another won't be queued, but done will still be called when said queued reload is finished.

reloadURLStructure (done func())

func replaceVariables

replaceVariables (in string, vars []string, vals map[string]interface{}, label string, escape bool) string
References: fmt.Sprintf, logrus.Fields, os.Getenv, strings.HasPrefix, strings.Replace, strings.ToUpper, url.QueryEscape.

func resetHandler

resetHandler will try to queue a reload. If fn is nil and block=true was in the URL parameters, it will block until the reload is done. Otherwise, it won't block and fn will be called once the reload is finished.

resetHandler (fn func()) http.HandlerFunc
References: http.Request, http.ResponseWriter, http.StatusOK, logrus.Fields, sync.WaitGroup.

func responseMWAppendEnabled

responseMWAppendEnabled (chain *[]TykResponseHandler, responseMW TykResponseHandler) bool

func responseProcessorByName

responseProcessorByName (name string, baseHandler BaseTykResponseHandler) TykResponseHandler

func rotateOauthClient

rotateOauthClient (keyName,apiID string) (interface{}, int)
References: http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, logrus.Fields.

func rotateOauthClientHandler

rotateOauthClientHandler (w http.ResponseWriter, r *http.Request)
References: mux.Vars.

func rpcReloadLoop

rpcReloadLoop (rpcKey string)

func saveRPCDefinitionsBackup

saveRPCDefinitionsBackup (list string) error
References: crypto.Encrypt, crypto.GetPaddedString, errors.New, json.Valid, storage.RedisCluster.

func saveRPCPoliciesBackup

saveRPCPoliciesBackup (list string) error
References: crypto.Encrypt, crypto.GetPaddedString, errors.New, json.Valid, storage.RedisCluster.

func schemaHandler

schemaHandler (w http.ResponseWriter, r *http.Request)
References: http.MethodGet, http.StatusNotFound, http.StatusOK, oas.GetOASSchema.

func setBasicAuthSessionPassword

setBasicAuthSessionPassword (session *user.SessionState)
References: bcrypt.GenerateFromPassword, storage.HashStr, user.HashBCrypt, user.HashPlainText, user.HashType.

func setCurrentHealthCheckInfo

setCurrentHealthCheckInfo (h map[string]model.HealthCheckItem)

func setTestMode

setTestMode (v bool)

func setUpConsul

setUpConsul () error
References: kv.NewConsul.

func setUpVault

setUpVault () error
References: kv.NewVault.

func setupGlobals

Create all globals and init connection handlers

setupGlobals ()
References: certs.NewCertificateManager, certs.NewSlaveCertManager, checkup.Run, dnscache.NewDnsCacheManager, filepath.Join, htmltemplate.Must, htmltemplate.ParseGlob, rpc.Purger, serializer.PROTOBUF_SERIALIZER, storage.RedisCluster, texttemplate.Must, texttemplate.ParseGlob, time.Duration, time.Second.

func setupInstrumentation

setupInstrumentation handles all the initialisation of the instrumentation handler

setupInstrumentation ()
References: cli.LogInstrumentation, os.Getenv.

func setupLogger

setupLogger ()
References: gas.Dial, grayloghook.NewGraylogHook, logrus.ErrorLevel, logrus.FatalLevel, logrus.Fields, logrus.Hook, logrus.Level, logrus.PanicLevel, logrussentry.NewSentryHook, logrussyslog.NewSyslogHook, logstashhook.DefaultFormatter, logstashhook.New, net.Conn, net.Dial, syslog.LOG_INFO.

func setupPortsWhitelist

setupPortsWhitelist ()
References: config.PortWhiteList.

func shouldReload

shouldReload returns true if we should perform any reload. Reloads happens if we have reload callback queued.

shouldReload () ([]func(), bool)

func skipSpecBecauseInvalid

skipSpecBecauseInvalid (spec *APISpec, logger *logrus.Entry) bool
References: strings.Contains, url.Parse.

func start

start ()
References: scheduler.NewJob, scheduler.NewScheduler, time.Duration, time.Second, time.Tick.

func startDRL

startDRL ()
References: drl.DRL.

func startPubSubLoop

startPubSubLoop ()
References: storage.RedisCluster, time.Second.

func startRateLimitNotifications

startRateLimitNotifications ()
References: time.Duration, time.Second, time.Sleep.

func startServer

startServer ()
References: mux.NewRouter.

func syncAPISpecs

syncAPISpecs () (int, error)

func syncPolicies

syncPolicies () (int, error)
References: user.Policy.

func traceHandler

Tracing request Used to test API definition by sending sample request, and analysisng output of both response and logs


requestBody:

content:
  application/json:
    schema:
      "$ref": "#/definitions/traceRequest"
    examples:
      request:
        method: GET
        path: /get
        headers:
           Authorization: key
      spec:
        api_name: "Test"

responses:

200:
  description: Success tracing request
  schema:
    "$ref": "#/definitions/traceResponse"
  examples:
    message: "ok"
    response:
      code: 200
      headers:
        Header: value
      body: body-value
    logs: {...}\n{...}

traceHandler (w http.ResponseWriter, r *http.Request)
References: apidef.APIDefinition, bytes.Buffer, http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, httptest.NewRecorder, httputil.DumpRequest, httputil.DumpResponse, json.NewDecoder, logrus.DebugLevel, logrus.JSONFormatter, logrus.New, logrus.NewEntry, model.MergedAPI, mux.NewRouter.

func updateKeyInStore

updateKeyInStore updates the API key in the specified KV store

updateKeyInStore (keyPath,newKey string)
References: kv.Store, strings.HasPrefix, strings.TrimPrefix.

func updateOauthClient

Update Client

updateOauthClient (keyName,apiID string, r *http.Request) (interface{}, int)
References: http.StatusBadRequest, http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, json.NewDecoder, logrus.Fields.

func urlRewrite

urlRewrite (meta *apidef.URLRewriteMeta, r *http.Request) (string, error)
References: apidef.Any, fmt.Errorf, regexp.Compile, strconv.Itoa, strings.Replace, url.PathUnescape.

func validateOAS

validateOAS (next http.HandlerFunc) http.HandlerFunc
References: apidef.ErrImportWithTykExtension, apidef.ErrPayloadWithoutTykExtension, bytes.NewReader, http.MethodPost, http.MethodPut, http.Request, http.ResponseWriter, http.StatusBadRequest, ioutil.NopCloser, oas.GetValidationOptionsFromConfig, oas.ValidateOASObject, strings.HasSuffix.

func validatePublicKeys

validatePublicKeys (host string, conn *tls.Conn, spec *APISpec) bool
References: crypto.HexSHA256, x509.MarshalPKIXPublicKey.

func verifyPeerCertificatePinnedCheck

verifyPeerCertificatePinnedCheck (spec *APISpec, tlsConfig *tls.Config) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
References: crypto.HexSHA256, errors.New, x509.Certificate, x509.MarshalPKIXPublicKey, x509.ParseCertificate.

func writeOASAndAPIDefToFile

writeOASAndAPIDefToFile (fs afero.Fs, apiDef *apidef.APIDefinition, oasObj *oas.OAS) (error, int)

func writeToFile

writeToFile (fs afero.Fs, newDef interface{}, filename string) (error, int)
References: errors.New, filepath.Join, http.StatusInternalServerError, ioutil.WriteFile, json.MarshalIndent.

func loadAnalyticsPlugin

loadAnalyticsPlugin () bool
References: goplugin.GetAnalyticsHandler, logrus.Fields.

func processRecord

processRecord (record *analytics.AnalyticsRecord) error
References: errors.New, fmt.Sprint, time.Now, time.Since.

func goPluginFromRequest

goPluginFromRequest (r *http.Request) (*GoPluginMiddleware, bool)

func loadPlugin

loadPlugin loads the plugin file from m.Path, it will try converting it to the tyk version aware format: {plugin_name}{tyk_version}{os}_{arch}.so if the file doesn't exist then it will again but with a gw version that is not prefixed by 'v' later, it will try with m.path which can be {plugin_name}.so

loadPlugin () bool
References: fmt.Errorf, goplugin.FileSystemStorage, goplugin.GetHandler, goplugin.GetPluginFileNameToLoad, logrus.Fields.

func block

block (logger *logrus.Entry) (error, int)
References: errors.New, http.StatusForbidden.

func pass

pass () (error, int)
References: http.StatusOK.

func handleComplexityFailReason

handleComplexityFailReason (failReason ComplexityFailReason) (error, int)
References: http.StatusForbidden, http.StatusInternalServerError, http.StatusOK.

func checkForUnsupportedUsage

checkForUnsupportedUsage () error
References: errors.New.

func isGraphQLConfigVersion1

isGraphQLConfigVersion1 () bool
References: apidef.GraphQLConfigVersion1, apidef.GraphQLConfigVersionNone.

func isSupergraphAPIDefinition

isSupergraphAPIDefinition () bool
References: apidef.GraphQLExecutionModeSupergraph.

func websocketUpgradeAllowed

websocketUpgradeAllowed () bool
References: apidef.GraphQLConfigVersion1, apidef.GraphQLConfigVersionNone.

func websocketUpgradeUsesGraphQLProtocol

websocketUpgradeUsesGraphQLProtocol (r *http.Request) bool
References: gqlwebsocket.ProtocolGraphQLTransportWS, gqlwebsocket.ProtocolGraphQLWS, header.SecWebSocketProtocol.

func validateFieldRestrictions

validateFieldRestrictions (gqlRequest *graphql.Request, fieldRestrictionList graphql.FieldRestrictionList, schema *graphql.Schema) GraphqlGranularAccessResult
References: graphql.DefaultFieldsValidator.

func isHeartBeatStopped

isHeartBeatStopped () bool
References: atomic.LoadInt32.

func newRequest

newRequest (method,endpoint string) *http.Request
References: header.XTykHostname, header.XTykSessionID, http.NewRequest.

func sendHeartBeat

sendHeartBeat (req *http.Request, client *http.Client) error
References: errors.New, header.XTykNodeID, header.XTykNonce, http.StatusForbidden, http.StatusOK, json.NewDecoder.

func authorizationError

authorizationError (r *http.Request) (error, int)
References: errors.New, http.StatusBadRequest.

func getAuthType

getAuthType overrides BaseMiddleware.getAuthType.

getAuthType () string
References: apidef.HMACType.

func getRSACertificateIdAndSessionForKeyID

getRSACertificateIdAndSessionForKeyID (r *http.Request, keyId string) (string, user.SessionState, error)
References: errors.New.

func getSecretAndSessionForKeyID

getSecretAndSessionForKeyID (r *http.Request, keyId string) (string, user.SessionState, error)
References: errors.New.

func hasLowerCaseEscaped

hasLowerCaseEscaped (signature string) (bool, []string)

func replaceWithUpperCase

replaceWithUpperCase (originalSignature string, lowercaseList []string) string
References: strings.Replace, strings.ToUpper.

func setContextVars

setContextVars (r *http.Request, token string)

func checkPollerLoop

checkPollerLoop (ctx context.Context)
References: logrus.Fields.

func getHostKey

getHostKey (report HostHealthReport) string

func execCheck

execCheck ()
References: errors.Is, tunny.ErrPoolNotRunning.

func getStaggeredTime

getStaggeredTime () time.Duration
References: mathrand.Intn, mathrand.Seed, time.Duration, time.Now, time.Second.

func isOpen

isOpen () bool
References: atomic.LoadInt32.

func handleError

handleError (r *http.Request, blacklistedIP string) (error, int)
References: errors.New, http.StatusForbidden.

func getAuthType

getAuthType overrides BaseMiddleware.getAuthType.

getAuthType () string
References: apidef.JWTType.

func getBasePolicyID

getBasePolicyID (r *http.Request, claims jwt.MapClaims) (string, bool)

func getIdentityFromToken

getIdentityFromToken (token *jwt.Token) (string, error)

func getOAuthClientIDFromClaim

getOAuthClientIDFromClaim (claims jwt.MapClaims) string

func getPolicyIDFromToken

getPolicyIDFromToken (claims jwt.MapClaims) (string, bool)

func getSecretFromMultipleJWKURIs

getSecretFromMultipleJWKURIs (jwkURIs []apidef.JWK, kidVal interface{}, keyType string) (interface{}, error)
References: apidef.APIDefinition, apidef.JWK, cache.DefaultExpiration, errors.New.

func getSecretFromURL

getSecretFromURL (url string, kidVal interface{}, keyType string) (interface{}, error)
References: apidef.APIDefinition, base64.StdEncoding, cache.DefaultExpiration, errors.New.

func getSecretToVerifySignature

getSecretToVerifySignature (r *http.Request, token *jwt.Token) (interface{}, error)
References: base64.StdEncoding, errors.New.

func getUserIdFromClaim

getUserIdFromClaim (claims jwt.MapClaims) (string, error)

func legacyGetSecretFromURL

legacyGetSecretFromURL (url,kid,keyType string) (interface{}, error)
References: base64.StdEncoding, bytes.Contains, cache.DefaultExpiration, errors.New, http.Client, http.Transport, json.NewDecoder, strings.ToLower, tls.Config.

func processCentralisedJWT

processCentralisedJWT Will check a JWT token centrally against the secret stored in the API Definition.

processCentralisedJWT (r *http.Request, token *jwt.Token) (error, int)
References: apidef.JWTClaim, apidef.UnsetAuth, cache.DefaultExpiration, errors.New, fmt.Sprintf, http.StatusForbidden, http.StatusInternalServerError, http.StatusOK, md5.Sum, osin.ServerConfig, storage.RedisCluster.

func processOneToOneTokenMap

processOneToOneTokenMap (r *http.Request, token *jwt.Token) (error, int)
References: errors.New, http.StatusForbidden, http.StatusNotFound, http.StatusOK.

func reportLoginFailure

reportLoginFailure (tykId string, r *http.Request)

func specCacheKey

specCacheKey (spec *APISpec, prefix string) string

func timeValidateJWTClaims

timeValidateJWTClaims (c jwt.MapClaims) *jwt.ValidationError

func notifyReadOnly

notifyReadOnly () bool

func proxyForRequest

proxyForRequest (r *http.Request) *ReverseProxy
References: logrus.Fields.

func generateOAuthOutputFromOsinResponse

generateOAuthOutputFromOsinResponse (osinResponse *osin.Response) []byte
References: bytes.Buffer, json.NewEncoder.

func notifyClientOfNewOauth

notifyClientOfNewOauth (notification NewOAuthNotification)

func getAuthType

getAuthType overrides BaseMiddleware.getAuthType.

getAuthType () string
References: apidef.OAuthType.

func dummyErrorHandler

We don't want any of the error handling, we use our own

dummyErrorHandler (e error, w http.ResponseWriter, r *http.Request) bool

func getAuthType

getAuthType () string
References: apidef.OIDCType.

func getProviders

getProviders () ([]openid.Provider, error)
References: base64.StdEncoding, logrus.Fields, openid.NewProvider, openid.Provider.

func reportLoginFailure

reportLoginFailure (tykId string, r *http.Request)
References: logrus.Fields.

func getOrgHasNoSession

getOrgHasNoSession () bool

func setOrgHasNoSession

setOrgHasNoSession (val bool)

func buildNodeInfo

buildNodeInfo () []byte
References: json.Marshal, model.GWStats, model.HostDetails, model.NodeData, time.Second.

func cleanKey

cleanKey (keyName string) string
References: strings.Replace.

func deleteUsingTokenID

Function to handle fallback deletion using token ID

deleteUsingTokenID (key,orgId string, resetQuota bool, status int) (int, error)
References: http.StatusNotFound, storage.TokenID.

func fixKey

fixKey (keyName string) string

func getGroupLoginCallback

getGroupLoginCallback (synchroniserEnabled bool) func(userKey string, groupID string) interface{}
References: model.GroupLoginRequest, rpc.NewSyncForcer.

func hashKey

hashKey (in string) string
References: storage.HashStr.

func handleQuotaFailure

handleQuotaFailure (r *http.Request, token string) (error, int)
References: errors.New, http.StatusForbidden, request.RealIP.

func getSession

getSession (r *http.Request) *user.SessionState
References: fmt.Sprintf, storage.HashKey, storage.HashStr, user.SessionState.

func shouldEnable

shouldEnable () bool

func recordWorker

recordWorker ()
References: fmt.Sprintf, mathrand.Intn, mathrand.Seed, storage.HashKey, strings.HasPrefix, time.NewTimer, time.Now, time.Since.

func decodePayload

decodePayload (payload string) (string, string, error)
References: base64.StdEncoding, errors.New, strings.Split.

func getCacheKeyFromHeaders

getCacheKeyFromHeaders (r *http.Request) string

func isTimeStampExpired

isTimeStampExpired (timestamp string) bool
References: strconv.ParseInt, time.Now, time.Unix.

func getRequestPath

getRequestPath (r *http.Request) string

func isRequestSigningConfigValid

isRequestSigningConfigValid () bool
References: strings.HasPrefix.

func checkRequestLimit

checkRequestLimit (r *http.Request, sizeLimit int64) (error, int)
References: errors.New, header.ContentLength, http.StatusBadRequest, http.StatusOK, logrus.Fields, strconv.ParseInt.

func encodePayload

encodePayload (payload string, timestamp int64) string
References: base64.StdEncoding, fmt.Sprint.

func getTimeTTL

getTimeTTL (cacheTTL int64) int64
References: time.Now.

func addAuthInfo

addAuthInfo (outReq,req *http.Request)
References: core.GetUpstreamAuth.

func copyBuffer

copyBuffer (dst io.Writer, src io.Reader) (int64, error)
References: context.Canceled, errors.Is, io.EOF, io.ErrShortWrite, logrus.Fields.

func defaultTransport

defaultTransport (dialerTimeout float64) *http.Transport
References: http.Transport, net.Dialer, time.Duration, time.Second.

func flushInterval

flushInterval returns the p.FlushInterval value, conditionally overriding its value for a specific request/response.

flushInterval (res *http.Response) time.Duration

func handleGraphQL

handleGraphQL (roundTripper *TykRoundTripper, outreq *http.Request, w http.ResponseWriter) (*http.Response, bool, error)
References: apidef.RequestHeadersRewriteConfig, graphengine.ProxyOnlyHeadersConfig, graphengine.ReverseProxyHeadersConfig, graphengine.ReverseProxyParams, textproto.CanonicalMIMEHeaderKey.

func handleOutboundRequest

handleOutboundRequest (roundTripper *TykRoundTripper, outreq *http.Request, w http.ResponseWriter) (*http.Response, bool, time.Duration, error)
References: time.Now, time.Since.

func handleUpgradeResponse

handleUpgradeResponse (rw http.ResponseWriter, req *http.Request, res *http.Response) error
References: fmt.Errorf, http.Hijacker, io.ReadWriteCloser, ioutil.NopCloser, strings.NewReader.

func httpTransport

httpTransport (timeOut float64, rw http.ResponseWriter, req *http.Request, outReq *http.Request) *TykRoundTripper
References: http2.ConfigureTransport, http2.Transport, net.Conn, net.Dial, tls.Config, tls.RenegotiateFreelyAsClient.

func mockResponse

mockResponse (r *http.Request) (*http.Response, error)
References: bytes.NewBuffer, fmt.Errorf, header.ContentType, http.Header, http.Response, io.NopCloser, oas.Header.

func sendRequestToUpstream

sendRequestToUpstream (roundTripper *TykRoundTripper, outreq *http.Request) (*http.Response, error)

func setCommonNameVerifyPeerCertificate

setCommonNameVerifyPeerCertificate (tlsConfig *tls.Config, hostName string)
References: errors.New, time.Now, x509.Certificate, x509.NewCertPool, x509.ParseCertificate, x509.VerifyOptions.

func addPortFromObject

addPortFromObject (host string, obj *gabs.Container) string
References: strconv.Itoa.

func decodeToNameSpace

decodeToNameSpace (namespace string, jsonParsed *gabs.Container) interface{}

func decodeToNameSpaceAsArray

decodeToNameSpaceAsArray (namespace string, jsonParsed *gabs.Container) []*gabs.Container

func getServiceData

getServiceData (name string) (string, error)
References: http.Get, ioutil.ReadAll.

func isList

isList (val string) bool
References: strings.HasPrefix.

func rawListToObj

rawListToObj (rawData string) string

func doRollingWindowWrite

doRollingWindowWrite (r *http.Request, session *user.SessionState, rateLimiterKey string, apiLimit *user.APILimit, dryRun bool) bool
References: context.Context, rate.NewSlidingLogRedis, time.Duration, time.Now, time.Second.

func limitDRL

limitDRL (bucketKey string, apiLimit *user.APILimit, dryRun bool) bool
References: time.Duration, time.Now, time.Second.

func limitRedis

limitRedis (r *http.Request, session *user.SessionState, rateLimiterKey string, apiLimit *user.APILimit, dryRun bool) bool

func limitSentinel

limitSentinel (r *http.Request, session *user.SessionState, rateLimiterKey string, apiLimit *user.APILimit, dryRun bool) bool

func updateSessionQuota

updateSessionQuota updates session attached access rights.

When limits are defined, QuotaRemaining and QuotaRenews is updated for a matching access rights definition for an api, and the session root.

updateSessionQuota (session *user.SessionState, scope string, remaining int64, renews int64)

func flush

flush ()

func getPrefixBuffer

getPrefixBuffer (job,event,suffix string) prefixBuffer
References: bytes.Buffer.

func loop

loop ()
References: time.NewTicker.

func processCmd

processCmd (cmd *statsdEmitCmd)

func processComplete

processComplete (job string, status health.CompletionStatus, nanos int64)

func processEvent

processEvent (job,event,extra string)

func processGauge

processGauge (job,event string, value float64)
References: strconv.AppendFloat.

func processTiming

processTiming (job,event string, nanos int64)

func writeNanosToTimingBuf

writeNanosToTimingBuf (nanos int64)
References: strconv.AppendFloat, strconv.AppendInt, time.Millisecond.

func writeSanitizedKeys

writeSanitizedKeys (b *bytes.Buffer, keys ...string)

func writeStatsDMetric

assumes b is a well-formed statsd metric like "job.event:1|c\n" (including newline)

writeStatsDMetric (b []byte)

func stripFromHeaders

strips auth key from headers

stripFromHeaders (r *http.Request, config *apidef.AuthConfig)
References: strings.HasPrefix, strings.Join, strings.Split, strings.TrimSpace.

func stripFromParams

strips auth from query string params

stripFromParams (r *http.Request, config *apidef.AuthConfig)
References: url.Parse.

func controlProxy

controlProxy () *proxy

func getMainRouter

getMainRouter (m *proxyMux) *mux.Router

func mainProxy

mainProxy () *proxy

func mainRouter

mainRouter () *mux.Router

func newGateway

newGateway (genConf func(globalConf *config.Config)) *Gateway
References: cli.Init, config.Config, config.FillEnv, config.WriteDefault, context.Background, context.WithTimeout, filepath.Dir, filepath.Join, http.ErrServerClosed, http.Server, httputil.NewConnectionWatcher, ioutil.TempDir, mathrand.Intn, net.Listen, net.SplitHostPort, otel.InitOpenTelemetry, runtime.Caller, storage.HashMurmur64, strconv.Atoi, time.NewTicker, time.Second.

func reloadSimulation

simulate reloads in the background, i.e. writes to global variables that should not be accessed in a racy way like the policies and api specs maps.

reloadSimulation (ctx context.Context, gw *Gateway)
References: time.Millisecond, time.Sleep, user.Policy.

func start

start (genConf func(globalConf *config.Config)) *Gateway
References: context.Background, context.WithCancel, http.Request, test.HTTPTestRunner, test.HttpServerRunner, test.NewRequest, test.TestCase.

func testHttpHandler

testHttpHandler (gw *Gateway) *mux.Router
References: fmt.Sprintf, http.Error, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusInternalServerError, http.StatusMethodNotAllowed, http.StatusText, io.WriteString, ioutil.ReadAll, json.NewEncoder, mux.NewRouter, mux.Vars, strconv.Atoi, websocket.Upgrader.

func withAuth

withAuth (r *http.Request) *http.Request

func matchesMethod

matchesMethod checks if the given method matches the method required by the URLSpec for the current status.

matchesMethod (method string) bool

func matchesPath

matchesPath takes the input string and matches it against an internal regex. it will match the regex against the clean URL with stripped listen path first, then it will match against the full URL including the listen path as provided. APISpec to provide URL sanitization of the input is passed along.

matchesPath (reqPath string, api *APISpec) bool

func modeSpecificSpec

modeSpecificSpec returns the respective field of URLSpec if it matches the given mode. Deprecated: Usage should not increase.

modeSpecificSpec (mode URLStatus) (interface{}, bool)

func formatError

formatError (schemaErrors []gojsonschema.ResultError) error
References: errors.New.

func getMetaFromRequest

getMetaFromRequest (r *http.Request) *apidef.VirtualMeta
References: apidef.VirtualMeta.

func checkURL

checkURL (r string) bool
References: logrus.Fields, url.ParseRequestURI.

func getRequestMethod

getRequestMethod (m string) WebHookRequestMethod
References: logrus.Fields, strings.ToUpper.

func setHookFired

setHookFired will create an expiring key for the checksum of the event

setHookFired (checksum string)
References: logrus.Fields.

func getHttpResponse

getHttpResponse (r *http.Request) *http.Response
References: bytes.NewReader, http.Response, http.StatusText, ioutil.NopCloser.

func handleRequestLimits

handleRequestLimits (w http.ResponseWriter, r *http.Request) bool
References: http.MaxBytesReader, httputil.EntityTooLarge.

func copyHeader

copyHeader (dst,src http.Header)

func handleHTTP

handleHTTP (w http.ResponseWriter, req *http.Request)
References: http.DefaultTransport, http.Error, http.StatusServiceUnavailable, io.Copy.

func handleTunneling

handleTunneling (w http.ResponseWriter, r *http.Request)
References: http.Error, http.Hijacker, http.StatusInternalServerError, http.StatusOK, http.StatusServiceUnavailable, net.DialTimeout, time.Second.

func transfer

transfer (destination io.WriteCloser, source io.ReadCloser)
References: io.Copy.

func delayedFlush

delayedFlush ()

func stop

stop ()

func copy

copy creates a copy of the io.Reader when we read from it (lazy).

copy () error
References: io.Copy.

func addTCPService

addTCPService (spec *APISpec, modifier *tcp.Modifier, gw *Gateway)
References: logrus.Fields, net.Dial, tcp.Proxy.

func generateListener

generateListener (listenPort int, protocol string, gw *Gateway) (net.Listener, error)
References: http2.NextProtoTLS, net.Listen, strconv.Itoa, tls.Config, tls.Listen, tls.NoClientCert.

func getProxy

getProxy (listenPort int, conf config.Config) *proxy

func handle404

handle404 (w http.ResponseWriter, r *http.Request)
References: fmt.Fprint, fmt.Sprintf, http.StatusNotFound, http.StatusText.

func router

router (port int, protocol string, conf config.Config) *mux.Router

func serve

serve (gw *Gateway)
References: h2c.NewHandler, http.Server, http2.Server, net.SplitHostPort, strconv.Atoi, strconv.Itoa, time.Duration, time.Second.

func setRouter

setRouter (port int, protocol string, router *mux.Router, conf config.Config)
References: logrus.Fields.

func swap

swap (new *proxyMux, gw *Gateway)
References: context.Background, context.WithTimeout, time.Second.

func toRequest

toRequest (ignoreCanonicalMIMEHeaderKey bool) (*http.Request, error)
References: http.NewRequest, strings.NewReader.

func compileCachedPathSpec

compileCachedPathSpec (oldpaths []string, newpaths []apidef.CacheMeta, conf config.Config) []URLSpec

func compileCircuitBreakerPathSpec

compileCircuitBreakerPathSpec (paths []apidef.CircuitBreakerMeta, stat URLStatus, apiSpec *APISpec, conf config.Config) []URLSpec
References: backoff.StopBackOff, circuit.Breaker, circuit.BreakerReset, circuit.BreakerStop, circuit.BreakerTripped, circuit.NewRateBreaker, time.Duration, time.Second, time.Sleep.

func compileExtendedPathSpec

compileExtendedPathSpec (ignoreEndpointCase bool, paths []apidef.EndPointMeta, specType URLStatus, conf config.Config) []URLSpec

func compileGopluginPathsSpec

compileGopluginPathsSpec (paths []apidef.GoPluginMeta, stat URLStatus, _ *APISpec, conf config.Config) []URLSpec

func compileInjectedHeaderSpec

compileInjectedHeaderSpec (paths []apidef.HeaderInjectionMeta, stat URLStatus, conf config.Config) []URLSpec

func compileInternalPathsSpec

compileInternalPathsSpec (paths []apidef.InternalMeta, stat URLStatus, conf config.Config) []URLSpec

func compileMethodTransformSpec

compileMethodTransformSpec (paths []apidef.MethodTransformMeta, stat URLStatus, conf config.Config) []URLSpec

func compileMockResponsePathSpec

compileMockResponsePathSpec (ignoreEndpointCase bool, paths []apidef.MockResponseMeta, specType URLStatus, conf config.Config) []URLSpec

func compilePathSpec

compilePathSpec (paths []string, specType URLStatus, conf config.Config) []URLSpec

func compilePersistGraphQLPathSpec

compilePersistGraphQLPathSpec (paths []apidef.PersistGraphQLMeta, stat URLStatus, apiSpec *APISpec, conf config.Config) []URLSpec

func compileRateLimitPathsSpec

compileRateLimitPathsSpec (paths []apidef.RateLimitMeta, stat URLStatus, conf config.Config) []URLSpec

func compileRequestSizePathSpec

compileRequestSizePathSpec (paths []apidef.RequestSizeMeta, stat URLStatus, conf config.Config) []URLSpec

func compileTimeoutPathSpec

compileTimeoutPathSpec (paths []apidef.HardTimeoutMeta, stat URLStatus, conf config.Config) []URLSpec

func compileTrackedEndpointPathsSpec

compileTrackedEndpointPathsSpec (paths []apidef.TrackEndpointMeta, stat URLStatus, conf config.Config) []URLSpec

func compileTransformPathSpec

compileTransformPathSpec (paths []apidef.TemplateMeta, stat URLStatus, conf config.Config) []URLSpec
References: apidef.UseBlob, apidef.UseFile, errors.New.

func compileURLRewritesPathSpec

compileURLRewritesPathSpec (paths []apidef.URLRewriteMeta, stat URLStatus, conf config.Config) []URLSpec

func compileUnTrackedEndpointPathsSpec

compileUnTrackedEndpointPathsSpec (paths []apidef.TrackEndpointMeta, stat URLStatus, conf config.Config) []URLSpec

func compileValidateJSONPathsSpec

compileValidateJSONPathsSpec (paths []apidef.ValidatePathMeta, stat URLStatus, conf config.Config) []URLSpec
References: gojsonschema.NewGoLoader.

func compileVirtualPathsSpec

compileVirtualPathsSpec (paths []apidef.VirtualMeta, stat URLStatus, apiSpec *APISpec, conf config.Config) []URLSpec

func filterSprigFuncs

filterSprigFuncs () texttemplate.FuncMap
References: texttemplate.FuncMap.

func generateRegex

generateRegex (stringSpec string, newSpec *URLSpec, specType URLStatus, conf config.Config)
References: httputil.PreparePathRegexp, regexp.Compile.

func getExtendedPathSpecs

getExtendedPathSpecs (apiVersionDef apidef.VersionInfo, apiSpec *APISpec, conf config.Config) ([]URLSpec, bool)

func getPathSpecs

getPathSpecs (apiVersionDef apidef.VersionInfo, conf config.Config) ([]URLSpec, bool)

func loadBlobTemplate

loadBlobTemplate (blob string) (*texttemplate.Template, error)
References: apidef.Template, base64.StdEncoding.

func loadDefFromFilePath

loadDefFromFilePath (filePath string) (*APISpec, error)
References: apidef.APIDefinition, json.Unmarshal, model.MergedAPI, oas.OAS, openapi3.NewLoader, openapi3.ReadFromFile, os.ReadFile.

func loadFileTemplate

loadFileTemplate (path string) (*texttemplate.Template, error)
References: apidef.Template, filepath.Base.

func prepareSpecs

prepareSpecs (apiDefs []model.MergedAPI, gwConfig config.Config, fromRPC bool) []*APISpec

func processRPCDefinitions

processRPCDefinitions (apiCollection string, gw *Gateway) ([]*APISpec, error)
References: json.Unmarshal, model.MergedAPI, model.NewMergedAPIList.

func replaceConsulSecrets

replaceConsulSecrets (input *string) error
References: kv.Consul, strings.Replace, strings.TrimPrefix.

func replaceSecrets

replaceSecrets (in []byte) []byte
References: os.Getenv, strings.Contains, strings.Replace.

func replaceVaultSecrets

replaceVaultSecrets (input *string) error
References: errors.New, fmt.Sprintf, kv.Vault, strings.Replace.

func checkClockSkew

checkClockSkew (dateHeaderValue string) bool
References: math.Abs, time.Now, time.Parse.

func checkLimit

checkLimit (sessionData *user.SessionState, key string, quotaMax,quotaRemaining,quotaRenews int64) bool
References: time.Now, time.Unix.

func getListener

getListener returns a net.Listener for this proxy. If useProxyProtocol is true it wraps the underlying listener to support proxyprotocol.

getListener () net.Listener
References: proxyproto.Listener.

func copyFromBackend

copyFromBackend (errc chan<- error)
References: io.Copy.

func copyToBackend

copyToBackend (errc chan<- error)
References: io.Copy.


Tests

Files: 82. Third party imports: 25. Imports from organisation: 8. Tests: 561. Benchmarks: 50.

Constants

const (
	internalTLSErr		= "tls: unrecognized name"
	badcertErr		= "tls: bad certificate"
	certNotMatchErr		= "Client TLS certificate is required"
	unknownCertAuthorityErr	= "unknown certificate authority"
)
const (
	extractorValueInput	= "testkey"

	extractorRegexExpr		= "prefix-(.*)"
	extractorRegexInput		= "prefix-testkey123"
	extractorRegexMatchIndex	= 0

	extractorXPathExpr	= "//object/key"
	extractorXPathInput	= "<object><key>thevalue</key></object>"

	extractorHeaderName	= "testheader"
	extractorParamName	= "testparam"
)
const (
	gqlContinentQuery	= `
query {
    continent(code: "NG"){
        code
        name
    }
}
`
	gqlContinentQueryVariable	= `
query ($code: ID!){
    continent(code: $code){
        name
    }
}`
	gqlStateQueryVariable	= `
query ($filter: StateFilterInput) {
  state(filter: $filter) {
    name
  }
}`
)
const (
	authRedirectUri		= "http://client.oauth.com"
	authRedirectUri2	= "http://client2.oauth.com"
	authClientID		= "1234"
	authClientSecret	= "aabbccdd"
)
const (
	RevokeOauthHashedToken		= "RevokeOauthHashedToken"
	RevokeOauthToken		= "RevokeOauthToken"
	RevokeOauthRefreshToken		= "RevokeOauthRefreshToken"
	RevokeOauthRefreshHashedToken	= "RevokeOauthRefreshHashedToken"	// we do  not support hashed refresh tokens yet

	DefaultOrg	= "default-org-id"
)
const apiDefListTest = `[{
	"api_id": "1",
	"definition": {
		"location": "header",
		"key": "version"
	},
	"auth": {"auth_header_name": "authorization"},
	"version_data": {
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/v1",
		"target_url": "` + TestHttpAny + `"
	}
}]`
const apiDefListTest2 = `[{
	"api_id": "1",
	"definition": {
		"location": "header",
		"key": "version"
	},
	"auth": {"auth_header_name": "authorization"},
	"version_data": {
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/v1",
		"target_url": "` + TestHttpAny + `"
	}
},
{
	"api_id": "2",
	"definition": {
		"location": "header",
		"key": "version"
	},
	"auth": {"auth_header_name": "authorization"},
	"version_data": {
		"versions": {
			"v2": {"name": "v2"}
		}
	},
	"proxy": {
		"listen_path": "/v2",
		"target_url": "` + TestHttpAny + `"
	}
}]`
const apiTestDef = `{
	"api_id": "1",
	"definition": {
		"location": "header",
		"key": "version"
	},
	"auth": {"auth_header_name": "authorization"},
	"version_data": {
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/v1",
		"target_url": "` + TestHttpAny + `"
	}
}`
const authKeyDef = `{
	"api_id": "31",
	"org_id": "default",
	"auth": {"auth_header_name": "authorization"},
	"version_data": {
		"not_versioned": true,
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/auth_key_test/",
		"target_url": "` + TestHttpAny + `"
	}
}`
const closedRLDefSmall = `{
	"api_id": "31445455",
	"org_id": "default",
	"auth": {"auth_header_name": "authorization"},
	"version_data": {
		"not_versioned": true,
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/rl_closed_test/",
		"target_url": "` + TestHttpAny + `"
	},
	"global_rate_limit": {
		"rate": 3,
		"per": 1
	}
}`
const consul = `
[{
	"Node": "foobar",
	"Address": "10.1.10.12",
	"ServiceID": "redis",
	"ServiceName": "redis",
	"ServicePort": 8000
},
{
	"Node": "foobar2",
	"Address": "10.1.10.13",
	"ServiceID": "redis",
	"ServiceName": "redis",
	"ServicePort": 8000
}]
`
const defaultTestPol = `{
"ID": "default-test",
"rate": 1000,
"per": 1,
"quota_max": 100,
"quota_renewal_rate": 60,
"access_rights": {
"41433797848f41a558c1573d3e55a410": {
"api_name": "My API",
"api_id": "41433797848f41a558c1573d3e55a410",
"versions": [
"Default"
]
}
},
"org_id": "54de205930c55e15bd000001",
"hmac_enabled": false

}`
const etcd = `{
	"action": "get",
	"node": {
		"key": "/services/single",
		"value": "httpbin.org:6000",
		"modifiedIndex": 6,
		"createdIndex": 6
	}
}`
const eureka_real = `{
	"application": {
		"name": "ROUTE",
		"instance": [{
			"hostName": "ip-172-31-57-136",
			"app": "ROUTE",
			"ipAddr": "172.31.57.136",
			"status": "UP",
			"overriddenstatus": "UNKNOWN",
			"port": {
				"@enabled": "true",
				"$": "60565"
			},
			"securePort": {
				"@enabled": "false",
				"$": "443"
			},
			"countryId": 1,
			"dataCenterInfo": {
				"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
				"name": "MyOwn"
			},
			"leaseInfo": {
				"renewalIntervalInSecs": 10,
				"durationInSecs": 10,
				"registrationTimestamp": 1460471383902,
				"lastRenewalTimestamp": 1460471403565,
				"serviceUpTimestamp": 1460471383340
			},
			"metadata": {
				"instanceId": "route:f673c15eebfc456a3c679a55d234a8ca",
				"payment": "perCall",
				"providerName": "MisterA"
			},
			"homePageUrl": "http:\/\/ip-172-31-57-136:60565\/",
			"statusPageUrl": "http:\/\/ip-172-31-57-136:60565\/info",
			"healthCheckUrl": "http:\/\/ip-172-31-57-136:60565\/health",
			"vipAddress": "route",
			"lastUpdatedTimestamp": 1460471383902,
			"lastDirtyTimestamp": 1460471429751,
			"actionType": "ADDED"
		}, {
			"hostName": "ip-172-31-13-37",
			"app": "ROUTE",
			"ipAddr": "172.31.13.37",
			"status": "UP",
			"overriddenstatus": "UNKNOWN",
			"port": {
				"@enabled": "true",
				"$": "50045"
			},
			"securePort": {
				"@enabled": "false",
				"$": "443"
			},
			"countryId": 1,
			"dataCenterInfo": {
				"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
				"name": "MyOwn"
			},
			"leaseInfo": {
				"renewalIntervalInSecs": 10,
				"durationInSecs": 10,
				"registrationTimestamp": 1460471387114,
				"lastRenewalTimestamp": 1460471407062,
				"serviceUpTimestamp": 1460471386750
			},
			"metadata": {
				"instanceId": "route:838ba7845f1fd63d94c10ca9efdf77a5",
				"payment": "flat",
				"providerName": "MissB"
			},
			"homePageUrl": "http:\/\/ip-172-31-13-37:50045\/",
			"statusPageUrl": "http:\/\/ip-172-31-13-37:50045\/info",
			"healthCheckUrl": "http:\/\/ip-172-31-13-37:50045\/health",
			"vipAddress": "route",
			"lastUpdatedTimestamp": 1460471387114,
			"lastDirtyTimestamp": 1460471360189,
			"actionType": "ADDED"
		}]
	}
}`
const expectedFeatures = `[{"name":"Patriots Path, Mendham, NJ 07945, USA","location":{"latitude":407838351,"longitude":-746143763}},{"name":"101 New Jersey 10, Whippany, NJ 07981, USA","location":{"latitude":408122808,"longitude":-743999179}},{"name":"U.S. 6, Shohola, PA 18458, USA","location":{"latitude":413628156,"longitude":-749015468}},{"name":"5 Conners Road, Kingston, NY 12401, USA","location":{"latitude":419999544,"longitude":-740371136}},{"name":"Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA","location":{"latitude":414008389,"longitude":-743951297}},{"name":"287 Flugertown Road, Livingston Manor, NY 12758, USA","location":{"latitude":419611318,"longitude":-746524769}},{"name":"4001 Tremley Point Road, Linden, NJ 07036, USA","location":{"latitude":406109563,"longitude":-742186778}},{"name":"352 South Mountain Road, Wallkill, NY 12589, USA","location":{"latitude":416802456,"longitude":-742370183}},{"name":"Bailey Turn Road, Harriman, NY 10926, USA","location":{"latitude":412950425,"longitude":-741077389}},{"name":"193-199 Wawayanda Road, Hewitt, NJ 07421, USA","location":{"latitude":412144655,"longitude":-743949739}},{"name":"406-496 Ward Avenue, Pine Bush, NY 12566, USA","location":{"latitude":415736605,"longitude":-742847522}},{"name":"162 Merrill Road, Highland Mills, NY 10930, USA","location":{"latitude":413843930,"longitude":-740501726}},{"name":"Clinton Road, West Milford, NJ 07480, USA","location":{"latitude":410873075,"longitude":-744459023}},{"name":"16 Old Brook Lane, Warwick, NY 10990, USA","location":{"latitude":412346009,"longitude":-744026814}},{"name":"3 Drake Lane, Pennington, NJ 08534, USA","location":{"latitude":402948455,"longitude":-747903913}},{"name":"6324 8th Avenue, Brooklyn, NY 11220, USA","location":{"latitude":406337092,"longitude":-740122226}},{"name":"1 Merck Access Road, Whitehouse Station, NJ 08889, USA","location":{"latitude":406421967,"longitude":-747727624}},{"name":"78-98 Schalck Road, Narrowsburg, NY 12764, USA","location":{"latitude":416318082,"longitude":-749677716}},{"name":"282 Lakeview Drive Road, Highland Lake, NY 12743, USA","location":{"latitude":415301720,"longitude":-748416257}},{"name":"330 Evelyn Avenue, Hamilton Township, NJ 08619, USA","location":{"latitude":402647019,"longitude":-747071791}},{"name":"New York State Reference Route 987E, Southfields, NY 10975, USA","location":{"latitude":412567807,"longitude":-741058078}},{"name":"103-271 Tempaloni Road, Ellenville, NY 12428, USA","location":{"latitude":416855156,"longitude":-744420597}},{"name":"1300 Airport Road, North Brunswick Township, NJ 08902, USA","location":{"latitude":404663628,"longitude":-744820157}},{"location":{"latitude":407113723,"longitude":-749746483}},{"location":{"latitude":402133926,"longitude":-743613249}},{"location":{"latitude":400273442,"longitude":-741220915}},{"location":{"latitude":411236786,"longitude":-744070769}},{"name":"211-225 Plains Road, Augusta, NJ 07822, USA","location":{"latitude":411633782,"longitude":-746784970}},{"location":{"latitude":415830701,"longitude":-742952812}},{"name":"165 Pedersen Ridge Road, Milford, PA 18337, USA","location":{"latitude":413447164,"longitude":-748712898}},{"name":"100-122 Locktown Road, Frenchtown, NJ 08825, USA","location":{"latitude":405047245,"longitude":-749800722}},{"location":{"latitude":418858923,"longitude":-746156790}},{"name":"650-652 Willi Hill Road, Swan Lake, NY 12783, USA","location":{"latitude":417951888,"longitude":-748484944}},{"name":"26 East 3rd Street, New Providence, NJ 07974, USA","location":{"latitude":407033786,"longitude":-743977337}},{"location":{"latitude":417548014,"longitude":-740075041}},{"location":{"latitude":410395868,"longitude":-744972325}},{"location":{"latitude":404615353,"longitude":-745129803}},{"name":"611 Lawrence Avenue, Westfield, NJ 07090, USA","location":{"latitude":406589790,"longitude":-743560121}},{"name":"18 Lannis Avenue, New Windsor, NY 12553, USA","location":{"latitude":414653148,"longitude":-740477477}},{"name":"82-104 Amherst Avenue, Colonia, NJ 07067, USA","location":{"latitude":405957808,"longitude":-743255336}},{"name":"170 Seven Lakes Drive, Sloatsburg, NY 10974, USA","location":{"latitude":411733589,"longitude":-741648093}},{"name":"1270 Lakes Road, Monroe, NY 10950, USA","location":{"latitude":412676291,"longitude":-742606606}},{"name":"509-535 Alphano Road, Great Meadows, NJ 07838, USA","location":{"latitude":409224445,"longitude":-748286738}},{"name":"652 Garden Street, Elizabeth, NJ 07202, USA","location":{"latitude":406523420,"longitude":-742135517}},{"name":"349 Sea Spray Court, Neptune City, NJ 07753, USA","location":{"latitude":401827388,"longitude":-740294537}},{"name":"13-17 Stanley Street, West Milford, NJ 07480, USA","location":{"latitude":410564152,"longitude":-743685054}},{"name":"47 Industrial Avenue, Teterboro, NJ 07608, USA","location":{"latitude":408472324,"longitude":-740726046}},{"name":"5 White Oak Lane, Stony Point, NY 10980, USA","location":{"latitude":412452168,"longitude":-740214052}},{"name":"Berkshire Valley Management Area Trail, Jefferson, NJ, USA","location":{"latitude":409146138,"longitude":-746188906}},{"name":"1007 Jersey Avenue, New Brunswick, NJ 08901, USA","location":{"latitude":404701380,"longitude":-744781745}},{"name":"6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA","location":{"latitude":409642566,"longitude":-746017679}},{"name":"1358-1474 New Jersey 57, Port Murray, NJ 07865, USA","location":{"latitude":408031728,"longitude":-748645385}},{"name":"367 Prospect Road, Chester, NY 10918, USA","location":{"latitude":413700272,"longitude":-742135189}},{"name":"10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA","location":{"latitude":404310607,"longitude":-740282632}},{"name":"11 Ward Street, Mount Arlington, NJ 07856, USA","location":{"latitude":409319800,"longitude":-746201391}},{"name":"300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA","location":{"latitude":406685311,"longitude":-742108603}},{"name":"43 Dreher Road, Roscoe, NY 12776, USA","location":{"latitude":419018117,"longitude":-749142781}},{"name":"Swan Street, Pine Island, NY 10969, USA","location":{"latitude":412856162,"longitude":-745148837}},{"name":"66 Pleasantview Avenue, Monticello, NY 12701, USA","location":{"latitude":416560744,"longitude":-746721964}},{"location":{"latitude":405314270,"longitude":-749836354}},{"location":{"latitude":414219548,"longitude":-743327440}},{"name":"565 Winding Hills Road, Montgomery, NY 12549, USA","location":{"latitude":415534177,"longitude":-742900616}},{"name":"231 Rocky Run Road, Glen Gardner, NJ 08826, USA","location":{"latitude":406898530,"longitude":-749127080}},{"name":"100 Mount Pleasant Avenue, Newark, NJ 07104, USA","location":{"latitude":407586880,"longitude":-741670168}},{"name":"517-521 Huntington Drive, Manchester Township, NJ 08759, USA","location":{"latitude":400106455,"longitude":-742870190}},{"location":{"latitude":400066188,"longitude":-746793294}},{"name":"40 Mountain Road, Napanoch, NY 12458, USA","location":{"latitude":418803880,"longitude":-744102673}},{"location":{"latitude":414204288,"longitude":-747895140}},{"location":{"latitude":414777405,"longitude":-740615601}},{"name":"48 North Road, Forestburgh, NY 12777, USA","location":{"latitude":415464475,"longitude":-747175374}},{"location":{"latitude":404062378,"longitude":-746376177}},{"location":{"latitude":405688272,"longitude":-749285130}},{"location":{"latitude":400342070,"longitude":-748788996}},{"location":{"latitude":401809022,"longitude":-744157964}},{"name":"9 Thompson Avenue, Leonardo, NJ 07737, USA","location":{"latitude":404226644,"longitude":-740517141}},{"location":{"latitude":410322033,"longitude":-747871659}},{"location":{"latitude":407100674,"longitude":-747742727}},{"name":"213 Bush Road, Stone Ridge, NY 12484, USA","location":{"latitude":418811433,"longitude":-741718005}},{"location":{"latitude":415034302,"longitude":-743850945}},{"location":{"latitude":411349992,"longitude":-743694161}},{"name":"1-17 Bergen Court, New Brunswick, NJ 08901, USA","location":{"latitude":404839914,"longitude":-744759616}},{"name":"35 Oakland Valley Road, Cuddebackville, NY 12729, USA","location":{"latitude":414638017,"longitude":-745957854}},{"location":{"latitude":412127800,"longitude":-740173578}},{"location":{"latitude":401263460,"longitude":-747964303}},{"location":{"latitude":412843391,"longitude":-749086026}},{"location":{"latitude":418512773,"longitude":-743067823}},{"name":"42-102 Main Street, Belford, NJ 07718, USA","location":{"latitude":404318328,"longitude":-740835638}},{"location":{"latitude":419020746,"longitude":-741172328}},{"location":{"latitude":404080723,"longitude":-746119569}},{"location":{"latitude":401012643,"longitude":-744035134}},{"location":{"latitude":404306372,"longitude":-741079661}},{"location":{"latitude":403966326,"longitude":-748519297}},{"location":{"latitude":405002031,"longitude":-748407866}},{"location":{"latitude":409532885,"longitude":-742200683}},{"location":{"latitude":416851321,"longitude":-742674555}},{"name":"3387 Richmond Terrace, Staten Island, NY 10303, USA","location":{"latitude":406411633,"longitude":-741722051}},{"name":"261 Van Sickle Road, Goshen, NY 10924, USA","location":{"latitude":413069058,"longitude":-744597778}},{"location":{"latitude":418465462,"longitude":-746859398}},{"location":{"latitude":411733222,"longitude":-744228360}},{"name":"3 Hasta Way, Newton, NJ 07860, USA","location":{"latitude":410248224,"longitude":-747127767}}]`
const gqlCountriesSchema = `directive @cacheControl(
  maxAge: Int
  scope: CacheControlScope
) on FIELD_DEFINITION | OBJECT | INTERFACE
enum CacheControlScope {
  PUBLIC
  PRIVATE
}

type Continent {
  code: ID!
  name: String!
  countries: [Country!]!
}

input ContinentFilterInput {
  code: StringQueryOperatorInput
}

type Country {
  code: ID!
  name: String!
  native: String!
  phone: String!
  continent: Continent!
  capital: String
  currency: String
  languages: [Language!]!
  emoji: String!
  emojiU: String!
  states: [State!]!
}

input CountryFilterInput {
  code: StringQueryOperatorInput
  currency: StringQueryOperatorInput
  continent: StringQueryOperatorInput
}

type Language {
  code: ID!
  name: String
  native: String
  rtl: Boolean!
}

input LanguageFilterInput {
  code: StringQueryOperatorInput
}

input StateFilterInput{
  code: StringQueryOperatorInput
  compulsory: String!
}

type Query {
  continents(filter: ContinentFilterInput): [Continent!]!
  continent(code: ID!): Continent
  countries(filter: CountryFilterInput): [Country!]!
  country(code: ID!): Country
  languages(filter: LanguageFilterInput): [Language!]!
  language(code: ID!): Language
  state(filter: StateFilterInput): [State!]!
}

type State {
  code: String
  name: String!
  country: Country!
}

input StringQueryOperatorInput {
  eq: String
  ne: String
  in: [String]
  nin: [String]
  regex: String
  glob: String
}

scalar Upload`
const gqlCountriesSilentTypeIntrospectionQuery = `{
  __type(name:"Country") {
    name
    fields {
      name
      type {
        kind
      }
    }
  }
}`
const gqlCountriesTypeIntrospectionQuery = `query IntrospectionQuery {
  __type(name:"Country") {
    name
    fields {
      name
      type {
        kind
      }
    }
  }
}`
const gqlCountriesTypeIntrospectionQueryWithMultipleFields = `query IntrospectionQuery {
  countries {
    name
    continent {
      code
      name
      countries {
        code
      }
    }
  }
  __type(name:"Country") {
    name
  }
}`
const gqlIntrospectionQuery = `query IntrospectionQuery {
  __schema {
    queryType {
      name
    }
    mutationType {
      name
    }
    subscriptionType {
      name
    }
    types {
      ...FullType
    }
    directives {
      name
      description
      locations
      args {
        ...InputValue
      }
    }
  }
}

fragment FullType on __Type {
  kind
  name
  description
  fields(includeDeprecated: true) {
    name
    description
    args {
      ...InputValue
    }
    type {
      ...TypeRef
    }
    isDeprecated
    deprecationReason
  }
  inputFields {
    ...InputValue
  }
  interfaces {
    ...TypeRef
  }
  enumValues(includeDeprecated: true) {
    name
    description
    isDeprecated
    deprecationReason
  }
  possibleTypes {
    ...TypeRef
  }
}

fragment InputValue on __InputValue {
  name
  description
  type {
    ...TypeRef
  }
  defaultValue
}

fragment TypeRef on __Type {
  kind
  name
  ofType {
    kind
    name
    ofType {
      kind
      name
      ofType {
        kind
        name
        ofType {
          kind
          name
          ofType {
            kind
            name
            ofType {
              kind
              name
              ofType {
                kind
                name
              }
            }
          }
        }
      }
    }
  }
}`
const gqlInvalidCountriesQuery = `{
  countries {
    name
    continent {
      code
      name
      countries {
        code
      }
    }
}`
const gqlMergedSupergraphSDL = `type Query {
	me: User
	allUsers: [User]
	topProducts(first: Int = 5): [Product]
}

type Subscription {
	review: Review!
}

type User {
	id: ID!
	username: String!
	reviews: [Review]
	account: [BankAccount!]
}

type BankAccount {
    number: String
    balance: Float 
}

type Product {
	upc: String!
	name: String!
	price: Int!
	reviews: [Review]
}

type Review {
	body: String!
	author: User!
	product: Product!
}`
const gqlProxyUpstreamSchema = `type Query {
	hello(name: String!): String!
	httpMethod: String!
}`
const gqlSchemaIntrospectionQueryWithMultipleFields = `query IntrospectionQuery {
  countries {
    name
    continent {
      code
      name
      countries {
        code
      }
    }
  }
  __schema {
    queryType {
      name
    }
  }
}`
const gqlSubgraphQueryReviews = `query Subgraph($_representations: [_Any!]!) {
  _entities(representations: $_representations) {
    ... on User {
      reviews {
		body
	  }
    }
  }
}`
const gqlSubgraphSDLAccounts = `extend type Query {
	me: User
	allUsers: [User]
} 

type User @key(fields: "id") { 
	id: ID! 
	username: String!
}`
const gqlSubgraphSDLBankAccounts = `
extend type User @key(fields: "id") {
  id: ID! @extends
  account: [BankAccount!]
}

type BankAccount {
  number: String
  balance: Float
}
`
const gqlSubgraphSDLReviews = `type Review {
	body: String!
	author: User! @provides(fields: "username")
	product: Product!
}

extend type User @key(fields: "id") {
	id: ID! @external
	reviews: [Review]
}

extend type Product @key(fields: "upc") {
	upc: String! @external
	reviews: [Review]
}`
const gqlSubgraphSchemaAccounts = `scalar _Any
scalar _FieldSet
union _Entity = User

type _Service {
  sdl: String
}

type Query {
  me: User
  allUsers: [User]
  _entities(representations: [_Any!]!): [_Entity]!
  _service: _Service!
}

type User @key(fields: "id"){ 
	id: ID! 
	username: String!
}

directive @external on FIELD_DEFINITION
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE
directive @extends on OBJECT | INTERFACE`
const gqlSubgraphSchemaBankAccounts = `
extend type User @key(fields: "id"){
    id: ID! @extends
    account: [BankAccount!]
}

type BankAccount {
    number: String
    balance: Float 
}

scalar _Any
scalar _FieldSet
union _Entity = User

type _Service {
  sdl: String
}

type Query {
  _entities(representations: [_Any!]!): [_Entity]!
  _service: _Service!
}

type BankAccount {
    number: String
    balance: Float 
}

type User @key(fields: "id"){
    id: ID! @extends
    account: [BankAccount!]
}

directive @external on FIELD_DEFINITION
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE
directive @extends on OBJECT | INTERFACE`
const gqlSubgraphSchemaReviews = `scalar _Any
scalar _FieldSet
union _Entity = User | Product

type _Service {
  sdl: String
}

type Query {
  _entities(representations: [_Any!]!): [_Entity]!
  _service: _Service!
}

type Review {
	body: String!
	author: User! @provides(fields: "username")
	product: Product!
}

type User @key(fields: "id") {
	id: ID! @external
	reviews: [Review]
}

type Product @key(fields: "upc") {
	upc: String! @external
	name: String! @external
	reviews: [Review] @requires(fields: "name")
}

directive @external on FIELD_DEFINITION
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE
directive @extends on OBJECT | INTERFACE`
const gqlSubgraphVariables = `{
	"_representations": [
		{
			"__typename": "User",
			"id": "1"
		}
	]
}`
const hmacAuthDef = `{
	"api_id": "1",
	"org_id": "default",
	"enable_signature_checking": true,
	"hmac_allowed_clock_skew": 5000,
	"auth": {"auth_header_name": "authorization"},
	"version_data": {
		"not_versioned": true,
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/v1",
		"target_url": "` + TestHttpAny + `"
	}
}`
// openssl rsa -in app.rsa -pubout > app.rsa.pub
const jwtRSAPubKey = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqZ4rwKF8qCExS7kpY4c
nJa/37FMkJNkalZ3OuslLB0oRL8T4c94kdF4aeNzSFkSe2n99IBI6Ssl79vbfMZb
+t06L0Q94k+/P37x7+/RJZiff4y1VGjrnrnMI2iu9l4iBBRYzNmG6eblroEMMWlg
k5tysHgxB59CSNIcD9gqk1hx4n/FgOmvKsfQgWHNlPSDTRcWGWGhB2/XgNVYG2pO
lQxAPqLhBHeqGTXBbPfGF9cHzixpsPr6GtbzPwhsQ/8bPxoJ7hdfn+rzztks3d6+
HWURcyNTLRe0mjXjjee9Z6+gZ+H+fS4pnP9tqT7IgU6ePUWTpjoiPtLexgsAa/ct
jQIDAQAB
-----END PUBLIC KEY-----
`
const jwtRSAPubKeyinvalid = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqZ4rwKF8qCExS7kpY4c
nJa/37FMkJNkalZ3OuslLB0oRL8T4c94kdF4aeNzSFkSe2n99IBI6Ssl79vbfMZb
+t06L0Q94k+/P37x7+/RJZiff4y1VGjrnrnMI2iu9l4iBBRYzNmG6eblroEMMWlg
k5tysHgxB59CSNIcD9gqk1hx4n/FgOmvKsfQgWHNlPSDTRcWGWGhB2/XgNVYG2pO
lQxAPqLhBHeqGTXBbPfGF9cHzixpsPr6GtbzPwhsQ/8bPxoJ7hdfn+rzztks3d6+
HWURcyNTLRe0mjXjjee9Z6+gZ+H+fS4pnP9tqT7IgU6ePUWTpjoiPtLexgsAa/ct
jQIDAQAB!!!!
-----END PUBLIC KEY-----
`
const keyRules = `{
	"last_check": 1402492859,
	"org_id": "53ac07777cbb8c2d53000002",
	"rate": 3,
	"per": 1,
	"quota_max": -1,
	"quota_renews": 1399567002,
	"quota_remaining": 10,
	"quota_renewal_rate": 300
}`
const keyRulesWithMetadata = `{
	"last_check": 1402492859,
	"org_id": "53ac07777cbb8c2d53000002",
	"rate": 3,
	"per": 1,
	"quota_max": -1,
	"quota_renews": 1399567002,
	"quota_remaining": 10,
	"quota_renewal_rate": 300,
	"meta_data": {"key": "meta", "foo": "keybar"}
}`
const mesosphere = `{
	"tasks": [{
		"id": "myservice.7fc21d4c-eabb-11e5-b381-066c48d09c8f",
		"host": "httpbin.org",
		"ports": [80],
		"startedAt": "2016-03-15T14:37:55.941Z",
		"stagedAt": "2016-03-15T14:37:52.792Z",
		"version": "2016-03-15T14:37:52.726Z",
		"slaveId": "d70867df-fdb2-4889-abeb-0829c742fded-S2",
		"appId": "/httpbin"
	}]
}`
const multiAuthBackwardsCompatible = `{
	"api_id": "31",
	"org_id": "default",
	"auth": {
		"auth_header_name": "token",
		"use_param": true
	},
	"version_data": {
		"not_versioned": true,
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/auth_key_test/",
		"target_url": "` + TestHttpAny + `"
	}
}`
const multiAuthDef = `{
	"api_id": "31",
	"org_id": "default",
	"auth": {
		"auth_header_name": "authorization",
		"param_name": "token",
		"use_param": true,
		"use_cookie": true,
		"cookie_name": "oreo"
	},
	"version_data": {
		"not_versioned": true,
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/auth_key_test/",
		"target_url": "` + TestHttpAny + `"
	}
}`
const multiAuthDev = `{
	"api_id": "55",
	"org_id": "default",
	"use_basic_auth": true,
	"use_standard_auth": true,
	"base_identity_provided_by": "auth_token",
	"auth_configs": {
		"basic": {"auth_header_name": "Authorization"},
		"authToken": {"auth_header_name": "x-standard-auth"}
	},
	"version_data": {
		"not_versioned": true,
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/v1",
		"target_url": "` + TestHttpAny + `"
	}
}`
const nested = `{
	"action": "get",
	"node": {
		"key": "/services/single",
		"value": "{\"hostname\": \"httpbin.org\", \"port\": \"80\"}",
		"modifiedIndex": 6,
		"createdIndex": 6
	}
}`
const nested_consul = `
[{
	"Name": "beep",
	"Data": "{\"hostname\": \"httpbin1.org\", \"port\": \"80\"}"
},
{
	"Name": "boop",
	"Data": "{\"hostname\": \"httpbin2.org\", \"port\": \"80\"}"
}]`
const nested_list = `{
	"action": "get",
	"node": {
		"key": "/services/single",
		"value": "[{\"hostname\": \"httpbin.org\", \"port\": \"80\"}, {\"hostname\": \"httpbin2.org\", \"port\": \"80\"}]",
		"modifiedIndex": 6,
		"createdIndex": 6
	}
}`
const openRLDefSmall = `{
	"api_id": "313232",
	"org_id": "default",
	"auth": {"auth_header_name": "authorization"},
	"use_keyless": true,
	"version_data": {
		"not_versioned": true,
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"proxy": {
		"listen_path": "/rl_test/",
		"target_url": "` + TestHttpAny + `"
	},
	"global_rate_limit": {
		"rate": 3,
		"per": 1
	}
}`
const sampleUptimeTestAPI = `{
	"api_id": "test",
	"use_keyless": true,
	"version_data": {
		"not_versioned": true,
		"versions": {
			"v1": {"name": "v1"}
		}
	},
	"uptime_tests": {
		"check_list": [
			{
				"url": "{{.Host1}}/get",
				"method": "GET"
			},
			{
				"url": "{{.Host2}}/get",
				"method": "GET"
			}
		]
	},
	"proxy": {
		"listen_path": "/",
		"enable_load_balancing": true,
		"check_host_against_uptime_tests": true,
		"target_list": [
			"{{.Host1}}",
			"{{.Host2}}"
		]
	}
}`
const testBatchRequest = `{
	"requests": [
	{
		"method": "GET",
		"headers": {
			"test-header-1": "test-1",
			"test-header-2": "test-2"
		},
		"relative_url": "get/?param1=this"
	},
	{
		"method": "POST",
		"body": "TEST BODY",
		"relative_url": "post/"
	},
	{
		"method": "PUT",
		"relative_url": "put/"
	}
	],
	"suppress_parallel_execution": true
}`
const testGQLQueryCountries = `
{
  countries{
    code
  }
}
`
const testGQLQueryCountry = `
query country($code: ID!){
  country(code: $code){
    code
  }
}`
const testGQLQueryCountryCode = `
query country($countryCode: ID!){
  country(code: $countryCode){
    code
  }
}`
const testOASForValidateRequest = `{
  "openapi": "3.0.0",
  "components": {
    "schemas": {
      "Country": {
        "properties": {
          "name": {
            "type": "string"
          }
        }
      },
      "Owner": {
        "properties": {
          "name": {
            "type": "string"
          },
          "country": {
            "$ref": "#/components/schemas/Country"
          }
        }
      },
      "Product": {
        "properties": {
          "name": {
            "type": "string"
          },
          "owner": {
            "$ref": "#/components/schemas/Owner"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiryOn": {
            "type": "string",
            "format": "date"
          }
        }
      }
    }
  },
  "info": {
    "title": "validate-request",
    "version": "1.0.0"
  },
  "paths": {
    "/post": {
      "post": {
        "operationId": "postpost",
        "parameters": [{
          "name": "id",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer"
          },
          "description": "description"
        }],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Product"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": ""
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "/"
    }
  ]
}`
const testQueryContinentCode = `
query continent($code: ID!) {
  continent(code: $code){
    code
  }
}`
const virtBatchTest = `function batchTest(request, session, config) {
    // Set up a response object
    var response = {
        Body: "",
        Headers: {
            "content-type": "application/json"
        },
        Code: 202
    }

    // Batch request
    var batch = {
        "requests": [
            {
                "method": "GET",
                "headers": {
                    "X-CertificateOuid": "X-CertificateOuid"
                },
                "body": "",
                "relative_url": "{upstream_URL}"
            },
            {
                "method": "GET",
                "headers": {
                    "X-CertificateOuid": "X-CertificateOuid"
                },
                "body": "",
                "relative_url": "{upstream_URL}"
            }
        ],
        "suppress_parallel_execution": false
    }

    var newBody = TykBatchRequest(JSON.stringify(batch))
    var asJS = JSON.parse(newBody)
    for (var i in asJS) {
        if (asJS[i].code == 0) {
            response.Code = 500
        }
    }
    return TykJsResponse(response, session.meta_data)
}`
const virtTestJS = `
function testVirtData(request, session, config) {
	var resp = {
		Body: "foobar",
		Headers: {
			"data-foo": config.config_data.foo,
			"data-bar-y": config.config_data.bar.y.toString(),
			"x-tyk-cache-action-set": "1",
			"x-tyk-cache-action-set-ttl": "10",
		},
		Code: 202
	}
	return TykJsResponse(resp, session.meta_data)
}
`

Vars

var (
	proxyOnErrorEnabled	= true
	keylessAuthEnabled	= true
	cacheEnabled		= true

	proxyOnErrorDisabled	= false
	keylessAuthDisabled	= false
	cacheDisabled		= false
)
var algoList = [4]string{"hmac-sha1", "hmac-sha256", "hmac-sha384", "hmac-sha512"}
var bundleWithBadSignature = map[string]string{
	"manifest.json": `
		{
		    "file_list": [],
		    "custom_middleware": {
		        "driver": "grpc",
		        "auth_check": {
		            "name": "MyAuthHook"
		        }
		    },
			"checksum": "d41d8cd98f00b204e9800998ecf8427e",
			"signature": "dGVzdC1wdWJsaWMta2V5"
		}
	`,
}

exampleData is a copy of testdata/route_guide_db.json. It's to avoid specifying file path with go run.

var exampleData = []byte(`[{
    "location": {
        "latitude": 407838351,
        "longitude": -746143763
    },
    "name": "Patriots Path, Mendham, NJ 07945, USA"
}, {
    "location": {
        "latitude": 408122808,
        "longitude": -743999179
    },
    "name": "101 New Jersey 10, Whippany, NJ 07981, USA"
}, {
    "location": {
        "latitude": 413628156,
        "longitude": -749015468
    },
    "name": "U.S. 6, Shohola, PA 18458, USA"
}, {
    "location": {
        "latitude": 419999544,
        "longitude": -740371136
    },
    "name": "5 Conners Road, Kingston, NY 12401, USA"
}, {
    "location": {
        "latitude": 414008389,
        "longitude": -743951297
    },
    "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
}, {
    "location": {
        "latitude": 419611318,
        "longitude": -746524769
    },
    "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
}, {
    "location": {
        "latitude": 406109563,
        "longitude": -742186778
    },
    "name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
}, {
    "location": {
        "latitude": 416802456,
        "longitude": -742370183
    },
    "name": "352 South Mountain Road, Wallkill, NY 12589, USA"
}, {
    "location": {
        "latitude": 412950425,
        "longitude": -741077389
    },
    "name": "Bailey Turn Road, Harriman, NY 10926, USA"
}, {
    "location": {
        "latitude": 412144655,
        "longitude": -743949739
    },
    "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
}, {
    "location": {
        "latitude": 415736605,
        "longitude": -742847522
    },
    "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
}, {
    "location": {
        "latitude": 413843930,
        "longitude": -740501726
    },
    "name": "162 Merrill Road, Highland Mills, NY 10930, USA"
}, {
    "location": {
        "latitude": 410873075,
        "longitude": -744459023
    },
    "name": "Clinton Road, West Milford, NJ 07480, USA"
}, {
    "location": {
        "latitude": 412346009,
        "longitude": -744026814
    },
    "name": "16 Old Brook Lane, Warwick, NY 10990, USA"
}, {
    "location": {
        "latitude": 402948455,
        "longitude": -747903913
    },
    "name": "3 Drake Lane, Pennington, NJ 08534, USA"
}, {
    "location": {
        "latitude": 406337092,
        "longitude": -740122226
    },
    "name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
}, {
    "location": {
        "latitude": 406421967,
        "longitude": -747727624
    },
    "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
}, {
    "location": {
        "latitude": 416318082,
        "longitude": -749677716
    },
    "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
}, {
    "location": {
        "latitude": 415301720,
        "longitude": -748416257
    },
    "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
}, {
    "location": {
        "latitude": 402647019,
        "longitude": -747071791
    },
    "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
}, {
    "location": {
        "latitude": 412567807,
        "longitude": -741058078
    },
    "name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
}, {
    "location": {
        "latitude": 416855156,
        "longitude": -744420597
    },
    "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
}, {
    "location": {
        "latitude": 404663628,
        "longitude": -744820157
    },
    "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
}, {
    "location": {
        "latitude": 407113723,
        "longitude": -749746483
    },
    "name": ""
}, {
    "location": {
        "latitude": 402133926,
        "longitude": -743613249
    },
    "name": ""
}, {
    "location": {
        "latitude": 400273442,
        "longitude": -741220915
    },
    "name": ""
}, {
    "location": {
        "latitude": 411236786,
        "longitude": -744070769
    },
    "name": ""
}, {
    "location": {
        "latitude": 411633782,
        "longitude": -746784970
    },
    "name": "211-225 Plains Road, Augusta, NJ 07822, USA"
}, {
    "location": {
        "latitude": 415830701,
        "longitude": -742952812
    },
    "name": ""
}, {
    "location": {
        "latitude": 413447164,
        "longitude": -748712898
    },
    "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
}, {
    "location": {
        "latitude": 405047245,
        "longitude": -749800722
    },
    "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
}, {
    "location": {
        "latitude": 418858923,
        "longitude": -746156790
    },
    "name": ""
}, {
    "location": {
        "latitude": 417951888,
        "longitude": -748484944
    },
    "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
}, {
    "location": {
        "latitude": 407033786,
        "longitude": -743977337
    },
    "name": "26 East 3rd Street, New Providence, NJ 07974, USA"
}, {
    "location": {
        "latitude": 417548014,
        "longitude": -740075041
    },
    "name": ""
}, {
    "location": {
        "latitude": 410395868,
        "longitude": -744972325
    },
    "name": ""
}, {
    "location": {
        "latitude": 404615353,
        "longitude": -745129803
    },
    "name": ""
}, {
    "location": {
        "latitude": 406589790,
        "longitude": -743560121
    },
    "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
}, {
    "location": {
        "latitude": 414653148,
        "longitude": -740477477
    },
    "name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
}, {
    "location": {
        "latitude": 405957808,
        "longitude": -743255336
    },
    "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
}, {
    "location": {
        "latitude": 411733589,
        "longitude": -741648093
    },
    "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
}, {
    "location": {
        "latitude": 412676291,
        "longitude": -742606606
    },
    "name": "1270 Lakes Road, Monroe, NY 10950, USA"
}, {
    "location": {
        "latitude": 409224445,
        "longitude": -748286738
    },
    "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
}, {
    "location": {
        "latitude": 406523420,
        "longitude": -742135517
    },
    "name": "652 Garden Street, Elizabeth, NJ 07202, USA"
}, {
    "location": {
        "latitude": 401827388,
        "longitude": -740294537
    },
    "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
}, {
    "location": {
        "latitude": 410564152,
        "longitude": -743685054
    },
    "name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
}, {
    "location": {
        "latitude": 408472324,
        "longitude": -740726046
    },
    "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
}, {
    "location": {
        "latitude": 412452168,
        "longitude": -740214052
    },
    "name": "5 White Oak Lane, Stony Point, NY 10980, USA"
}, {
    "location": {
        "latitude": 409146138,
        "longitude": -746188906
    },
    "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
}, {
    "location": {
        "latitude": 404701380,
        "longitude": -744781745
    },
    "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
}, {
    "location": {
        "latitude": 409642566,
        "longitude": -746017679
    },
    "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
}, {
    "location": {
        "latitude": 408031728,
        "longitude": -748645385
    },
    "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
}, {
    "location": {
        "latitude": 413700272,
        "longitude": -742135189
    },
    "name": "367 Prospect Road, Chester, NY 10918, USA"
}, {
    "location": {
        "latitude": 404310607,
        "longitude": -740282632
    },
    "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
}, {
    "location": {
        "latitude": 409319800,
        "longitude": -746201391
    },
    "name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
}, {
    "location": {
        "latitude": 406685311,
        "longitude": -742108603
    },
    "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
}, {
    "location": {
        "latitude": 419018117,
        "longitude": -749142781
    },
    "name": "43 Dreher Road, Roscoe, NY 12776, USA"
}, {
    "location": {
        "latitude": 412856162,
        "longitude": -745148837
    },
    "name": "Swan Street, Pine Island, NY 10969, USA"
}, {
    "location": {
        "latitude": 416560744,
        "longitude": -746721964
    },
    "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
}, {
    "location": {
        "latitude": 405314270,
        "longitude": -749836354
    },
    "name": ""
}, {
    "location": {
        "latitude": 414219548,
        "longitude": -743327440
    },
    "name": ""
}, {
    "location": {
        "latitude": 415534177,
        "longitude": -742900616
    },
    "name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
}, {
    "location": {
        "latitude": 406898530,
        "longitude": -749127080
    },
    "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
}, {
    "location": {
        "latitude": 407586880,
        "longitude": -741670168
    },
    "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
}, {
    "location": {
        "latitude": 400106455,
        "longitude": -742870190
    },
    "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
}, {
    "location": {
        "latitude": 400066188,
        "longitude": -746793294
    },
    "name": ""
}, {
    "location": {
        "latitude": 418803880,
        "longitude": -744102673
    },
    "name": "40 Mountain Road, Napanoch, NY 12458, USA"
}, {
    "location": {
        "latitude": 414204288,
        "longitude": -747895140
    },
    "name": ""
}, {
    "location": {
        "latitude": 414777405,
        "longitude": -740615601
    },
    "name": ""
}, {
    "location": {
        "latitude": 415464475,
        "longitude": -747175374
    },
    "name": "48 North Road, Forestburgh, NY 12777, USA"
}, {
    "location": {
        "latitude": 404062378,
        "longitude": -746376177
    },
    "name": ""
}, {
    "location": {
        "latitude": 405688272,
        "longitude": -749285130
    },
    "name": ""
}, {
    "location": {
        "latitude": 400342070,
        "longitude": -748788996
    },
    "name": ""
}, {
    "location": {
        "latitude": 401809022,
        "longitude": -744157964
    },
    "name": ""
}, {
    "location": {
        "latitude": 404226644,
        "longitude": -740517141
    },
    "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
}, {
    "location": {
        "latitude": 410322033,
        "longitude": -747871659
    },
    "name": ""
}, {
    "location": {
        "latitude": 407100674,
        "longitude": -747742727
    },
    "name": ""
}, {
    "location": {
        "latitude": 418811433,
        "longitude": -741718005
    },
    "name": "213 Bush Road, Stone Ridge, NY 12484, USA"
}, {
    "location": {
        "latitude": 415034302,
        "longitude": -743850945
    },
    "name": ""
}, {
    "location": {
        "latitude": 411349992,
        "longitude": -743694161
    },
    "name": ""
}, {
    "location": {
        "latitude": 404839914,
        "longitude": -744759616
    },
    "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
}, {
    "location": {
        "latitude": 414638017,
        "longitude": -745957854
    },
    "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
}, {
    "location": {
        "latitude": 412127800,
        "longitude": -740173578
    },
    "name": ""
}, {
    "location": {
        "latitude": 401263460,
        "longitude": -747964303
    },
    "name": ""
}, {
    "location": {
        "latitude": 412843391,
        "longitude": -749086026
    },
    "name": ""
}, {
    "location": {
        "latitude": 418512773,
        "longitude": -743067823
    },
    "name": ""
}, {
    "location": {
        "latitude": 404318328,
        "longitude": -740835638
    },
    "name": "42-102 Main Street, Belford, NJ 07718, USA"
}, {
    "location": {
        "latitude": 419020746,
        "longitude": -741172328
    },
    "name": ""
}, {
    "location": {
        "latitude": 404080723,
        "longitude": -746119569
    },
    "name": ""
}, {
    "location": {
        "latitude": 401012643,
        "longitude": -744035134
    },
    "name": ""
}, {
    "location": {
        "latitude": 404306372,
        "longitude": -741079661
    },
    "name": ""
}, {
    "location": {
        "latitude": 403966326,
        "longitude": -748519297
    },
    "name": ""
}, {
    "location": {
        "latitude": 405002031,
        "longitude": -748407866
    },
    "name": ""
}, {
    "location": {
        "latitude": 409532885,
        "longitude": -742200683
    },
    "name": ""
}, {
    "location": {
        "latitude": 416851321,
        "longitude": -742674555
    },
    "name": ""
}, {
    "location": {
        "latitude": 406411633,
        "longitude": -741722051
    },
    "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
}, {
    "location": {
        "latitude": 413069058,
        "longitude": -744597778
    },
    "name": "261 Van Sickle Road, Goshen, NY 10924, USA"
}, {
    "location": {
        "latitude": 418465462,
        "longitude": -746859398
    },
    "name": ""
}, {
    "location": {
        "latitude": 411733222,
        "longitude": -744228360
    },
    "name": ""
}, {
    "location": {
        "latitude": 410248224,
        "longitude": -747127767
    },
    "name": "3 Hasta Way, Newton, NJ 07860, USA"
}]`)
var grpcBundleWithAuthCheck = map[string]string{
	"manifest.json": `
		{
		    "file_list": [],
		    "custom_middleware": {
		        "driver": "grpc",
		        "auth_check": {
		            "name": "MyAuthHook"
		        }
		    },
			"checksum": "d41d8cd98f00b204e9800998ecf8427e"
		}
	`,
}
var (
	handlerTypes = []apidef.TykEventHandlerName{
		EH_LogHandler,
		EH_WebHook,
	}
)
var overrideResponseJSVM = map[string]string{
	"manifest.json": `
{
    "file_list": [],
    "custom_middleware": {
        "driver": "otto",
        "pre": [{
            "name": "pre",
            "path": "pre.js"
        }]
    },
	"checksum": "d41d8cd98f00b204e9800998ecf8427e"
}
`,
	"pre.js": `
var pre = new TykJS.TykMiddleware.NewMiddleware({});

pre.NewProcessRequest(function(request, session) {
	if (request.Params["response_body"]) {
		request.ReturnOverrides.ResponseBody = 'foobar'
	} else {
		request.ReturnOverrides.ResponseError = '{"foo": "bar"}'
	}

	request.ReturnOverrides.ResponseCode = parseInt(request.Params["status"])
	request.ReturnOverrides.ResponseHeaders = {"X-Foo": "Bar"}

	if (request.Params["override"]) {
		request.ReturnOverrides.OverrideError = true
	}
	return pre.ReturnData(request, {});
});
`,
}
var overrideResponsePython = map[string]string{
	"manifest.json": `
		{
		    "file_list": [
		        "middleware.py"
		    ],
		    "custom_middleware": {
		        "driver": "python",
		        "pre": [{
		            "name": "MyRequestHook"
		        }]
		    },
			"checksum": "81f585cdf7bf352e3c33ed62396b1e8e"
		}
	`,
	"middleware.py": `
from tyk.decorators import *
from gateway import TykGateway as tyk

@Hook
def MyRequestHook(request, response, session, metadata, spec):
	request.object.return_overrides.headers['X-Foo'] = 'Bar'
	request.object.return_overrides.response_code = int(request.object.params["status"])

	if request.object.params["response_body"] == "true":
		request.object.return_overrides.response_body = "foobar"
	else:
		request.object.return_overrides.response_error = "{\"foo\": \"bar\"}"

	if request.object.params["override"]:
		request.object.return_overrides.override_error = True

	return request, session
`,
}
var sess = user.SessionState{
	OrgID:		"TestBaseMiddleware_OrgSessionExpiry",
	DataExpires:	110,
}
var testBlackListIPData = []struct {
	remote, forwarded, xRealIP	string
	wantCode			int
}{
	{"127.0.0.1:80", "", "", http.StatusForbidden},		// remote exact match
	{"127.0.0.2:80", "", "", http.StatusForbidden},		// remote CIDR match
	{"10.0.0.1:80", "", "", http.StatusOK},			// no match
	{"10.0.0.1:80", "127.0.0.1", "", http.StatusForbidden},	// forwarded exact match
	{"10.0.0.1:80", "127.0.0.2", "", http.StatusForbidden},	// forwarded CIDR match
	{"10.0.0.1:80", "", "bob", http.StatusOK},		// no match
}
var (
	testBundlesPath = filepath.Join(testMiddlewarePath, "bundles")
)
var testJsonSchema = `{
    "title": "Person",
    "type": "object",
    "properties": {
        "firstName": {
            "type": "string"
        },
        "lastName": {
            "type": "string"
        },
        "age": {
            "description": "Age in years",
            "type": "integer",
            "minimum": 0
        },
		"objs":{
			"enum":["a","b","c"],
			"type":"string"
		}
    },
    "required": ["firstName", "lastName"]
}`
var testRewriterData = []struct {
	name		string
	pattern, to	string
	in, want	string
}{
	{
		"Encoded",
		"/test/payment-intents", "/change/to/me",
		"/test/payment%2Dintents", "/change/to/me",
	},
	{
		"MatchEncodedChars",
		"^(.+)%2[Dd](.+)$", "/change/to/me",
		"/test/payment%2Dintents", "/change/to/me",
	},
	{
		"Straight",
		"/test/straight/rewrite", "/change/to/me",
		"/test/straight/rewrite", "/change/to/me",
	},
	{
		"OneVal",
		"test/val/(.*)", "change/to/$1",
		"/test/val/VALUE", "change/to/VALUE",
	},
	{
		"OneVal Special Case",
		"test/val/(.*)", "/test/val/$1",
		"/test/val/VALUE%2C", "/test/val/VALUE%2C",
	},
	{
		"OneVal Special Case With Query Param Encoded",
		"test/val/(.*)", "/test/val/$1",
		"/test/val/VALUE%2C?a=te%2Cst", "/test/val/VALUE%2C?a=te%2Cst",
	},
	{
		"ThreeVals",
		"/test/val/(.*)/space/(.*)/and/then/(.*)", "/change/to/$1/$2/$3",
		"/test/val/ONE/space/TWO/and/then/THREE", "/change/to/ONE/TWO/THREE",
	},
	{
		"Reverse",
		"/test/val/(.*)/space/(.*)/and/then/(.*)", "/change/to/$3/$2/$1",
		"/test/val/ONE/space/TWO/and/then/THREE", "/change/to/THREE/TWO/ONE",
	},
	{
		"Missing",
		"/test/val/(.*)/space/(.*)/and/then/(.*)", "/change/to/$1/$2",
		"/test/val/ONE/space/TWO/and/then/THREE", "/change/to/ONE/TWO",
	},
	{
		"MissingAgain",
		"/test/val/(.*)/space/(.*)/and/then/(.*)", "/change/to/$3/$1",
		"/test/val/ONE/space/TWO/and/then/THREE", "/change/to/THREE/ONE",
	},
	{
		"QS",
		"(.*)", "$1&newParam=that",
		"/foo/bar?param1=this", "/foo/bar?param1=this&newParam=that",
	},
	{
		"QS2",
		"/test/val/(.*)/space/(.*)/and/then(.*)", "/change/to/$2/$1$3",
		"/test/val/ONE/space/TWO/and/then?param1=this", "/change/to/TWO/ONE?param1=this",
	},
}
var testWhiteListIPData = []struct {
	remote, forwarded, xRealIP	string
	wantCode			int
}{
	{"127.0.0.1:80", "", "", http.StatusOK},		// remote exact match
	{"127.0.0.2:80", "", "", http.StatusOK},		// remote CIDR match
	{"10.0.0.1:80", "", "", http.StatusForbidden},		// no match
	{"10.0.0.1:80", "127.0.0.1", "", http.StatusOK},	// forwarded exact match
	{"10.0.0.1:80", "127.0.0.2", "", http.StatusOK},	// forwarded CIDR match
	{"10.0.0.1:80", "", "bob", http.StatusForbidden},	// no match
}

Types

JwtCreator

This type doesn't have documentation.

Field name Field type Comment
type

func() *user.SessionState

No comment on field.
type JwtCreator func() *user.SessionState

TestAuth

This type doesn't have documentation.

Field name Field type Comment

apidef.AuthConfig

No comment on field.
HeaderKey

string

No comment on field.
QueryParam

string

No comment on field.
type TestAuth struct {
	apidef.AuthConfig
	HeaderKey	string
	QueryParam	string
}

answers

This type doesn't have documentation.

Field name Field type Comment
mu

sync.RWMutex

No comment on field.
ping

bool

No comment on field.
cancel

func()

No comment on field.
type answers struct {
	mu		sync.RWMutex
	ping, fail, up	bool
	cancel		func()
}

bindAPIDefFunc

This type doesn't have documentation.

Field name Field type Comment
type

func(*APISpec)

No comment on field.
type bindAPIDefFunc = func(*APISpec)

bindContextFunc

This type doesn't have documentation.

Field name Field type Comment
type

func(context.Context) context.Context

No comment on field.
type bindContextFunc = func(context.Context) context.Context

configTestReverseProxyDnsCache

This type doesn't have documentation.

Field name Field type Comment

*testing.T

No comment on field.
etcHostsMap

map[string][]string

No comment on field.
dnsConfig

config.DnsCacheConfig

No comment on field.
type configTestReverseProxyDnsCache struct {
	*testing.T

	etcHostsMap	map[string][]string
	dnsConfig	config.DnsCacheConfig
}

countingStorageHandler

This type doesn't have documentation.

Field name Field type Comment
deleteRawKeyMutex

*sync.Mutex

No comment on field.
deleteRawKeyCount

int

No comment on field.
type countingStorageHandler struct {
	deleteRawKeyMutex	*sync.Mutex
	deleteRawKeyCount	int
}

customListener

This type doesn't have documentation.

Field name Field type Comment
L

net.Listener

No comment on field.
type customListener struct {
	L net.Listener
}

gatewayGetHostDetailsTestCheckFn

This type doesn't have documentation.

Field name Field type Comment
type

func(*testing.T, *test.BufferedLogger, *Gateway)

No comment on field.
type gatewayGetHostDetailsTestCheckFn func(*testing.T, *test.BufferedLogger, *Gateway)

loginCredsOrToken

This type doesn't have documentation.

Field name Field type Comment
Username

string

No comment on field.
Password

string

No comment on field.
TokenBasedAuth

bool

No comment on field.
Token

string

No comment on field.
type loginCredsOrToken struct {
	Username	string
	Password	string
	TokenBasedAuth	bool
	Token		string
}

mockStore

This type doesn't have documentation.

Field name Field type Comment

SessionHandler

No comment on field.
DetailNotFound

bool

DetailNotFound is used to make mocked SessionDetail return (x,false), as if it don't find the session in the mocked storage.

type mockStore struct {
	SessionHandler
	//DetailNotFound is used to make mocked SessionDetail return (x,false), as if it don't find the session in the mocked storage.
	DetailNotFound	bool
}

modifiedMiddleware

modifiedMiddleware is a sample custom middleware component, must inherit TykMiddleware so you have access to spec and definition data

Field name Field type Comment

*BaseMiddleware

No comment on field.
type modifiedMiddleware struct {
	*BaseMiddleware
}

modifiedMiddlewareConfig

This type doesn't have documentation.

Field name Field type Comment
CustomData

string

No comment on field.
type modifiedMiddlewareConfig struct {
	CustomData string `mapstructure:"custom_data" json:"custom_data"`
}

routeGuideServer

This type doesn't have documentation.

Field name Field type Comment
savedFeatures

[]*pb.Feature

No comment on field.

pb.UnimplementedRouteGuideServer

No comment on field.
mu

sync.Mutex

No comment on field.
routeNotes

map[string][]*pb.RouteNote

No comment on field.
type routeGuideServer struct {
	savedFeatures	[]*pb.Feature	// read-only after initialized
	pb.UnimplementedRouteGuideServer
	mu		sync.Mutex	// protects routeNotes
	routeNotes	map[string][]*pb.RouteNote
}

server

server is used to implement helloworld.GreeterServer.

Field name Field type Comment

pbexample.UnimplementedGreeterServer

No comment on field.
type server struct {
	pbexample.UnimplementedGreeterServer
}

testAuthFailEventHandler

This type doesn't have documentation.

Field name Field type Comment
cb

func(config.EventMessage)

No comment on field.
type testAuthFailEventHandler struct {
	cb func(config.EventMessage)
}

testContextVarsData

This type doesn't have documentation.

Field name Field type Comment
Method

string

No comment on field.
URL

string

No comment on field.
Data

string

No comment on field.
ExpectedCtxDataObject

map[string]any

No comment on field.
Header

http.Header

No comment on field.
type testContextVarsData struct {
	Method			string
	URL			string
	Data			string
	ExpectedCtxDataObject	map[string]interface{}
	Header			http.Header
}

testEventHandler

This type doesn't have documentation.

Field name Field type Comment
cb

func(config.EventMessage)

No comment on field.
type testEventHandler struct {
	cb func(config.EventMessage)
}

testRewriterCase

This type doesn't have documentation.

Field name Field type Comment
name

string

No comment on field.
meta

*apidef.URLRewriteMeta

No comment on field.
reqMaker

func() *http.Request

No comment on field.
want

string

No comment on field.
type testRewriterCase struct {
	name		string
	meta		*apidef.URLRewriteMeta
	reqMaker	func() *http.Request
	want		string
}

tokenData

This type doesn't have documentation.

Field name Field type Comment
AccessToken

string

No comment on field.
RefreshToken

string

No comment on field.
type tokenData struct {
	AccessToken	string	`json:"access_token"`
	RefreshToken	string	`json:"refresh_token"`
}

Test functions

TestAPICertificate

References: config.Config, crypto.GenServerCertificate, http.Client, http.Transport, test.TestCase, testing.T, tls.Config, tls.VersionTLS12.

TestAPIClientAuthorizeAuthCode

References: http.MethodPost, http.StatusOK, test.TestCase, testing.T, url.Values.

TestAPIClientAuthorizeToken

References: http.MethodPost, http.StatusOK, json.NewDecoder, reflect.DeepEqual, test.TestCase, testing.T, url.Values.

TestAPIClientAuthorizeTokenWithPolicy

References: http.MethodPost, http.StatusOK, json.NewDecoder, reflect.DeepEqual, test.TestCase, testing.T, url.Values.

TestAPIDefinitionLoader

References: assert.Equal, assert.Error, assert.Len, assert.NoError, base64.StdEncoding, bytes.Buffer, ioutil.ReadFile, json.Unmarshal, testing.T, texttemplate.Template.

TestAPIExpiration

References: apidef.ExpirationTimeFormat, assert.Empty, assert.NotEmpty, fmt.Sprintf, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, time.Now.

TestAPILoaderValidation

References: testing.T.

TestAPILoopingName

References: assert.Equal, testing.T.

TestAPIMutualTLS

References: testing.T.

TestAPISpec_GetSessionLifetimeRespectsKeyExpiration

References: apidef.APIDefinition, assert.False, assert.True, testing.T.

TestAPISpec_SanitizeProxyPaths

References: apidef.APIDefinition, assert.Equal, http.MethodGet, http.NewRequest, testing.T.

TestAPISpec_StripListenPath

References: http.MethodGet, http.StatusOK, httptest.NewRecorder, test.Flaky, test.TestCase, testing.T.

TestAPISpec_isListeningOnPort

References: apidef.APIDefinition, assert.True, config.Config.

TestAPISpec_isStreamingAPI

References: assert.Equal, oas.OAS, openapi3.T, streams.ExtensionTykStreaming, testing.T.

TestAPISpec_setHasMock

References: apidef.APIDefinition, assert.False, assert.True, oas.Middleware, oas.MockResponse, oas.OAS, oas.Operation, oas.Operations, oas.XTykAPIGateway.

TestAPIsHavingShorterSubstringListenPathButLongerCustomDomain

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestAPIsHavingShorterSubstringListenPathButLongerCustomDomainAndListenPathsEndInSlash

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestAPIsHavingShorterSubstringListenPathButLongerCustomDomainAndListenPathsEndInSlashWithStripListenPathDisabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestAPIsHavingShorterSubstringListenPathButLongerCustomDomainAndListenPathsEndInSlashWithStripListenPathDisabledAndStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestAPIsHavingShorterSubstringListenPathButLongerCustomDomainAndListenPathsEndInSlashWithStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestAPIsHavingShorterSubstringListenPathButLongerCustomDomainWithStripListenPathDisabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestAPIsHavingShorterSubstringListenPathButLongerCustomDomainWithStripListenPathDisabledAndStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestAPIsHavingShorterSubstringListenPathButLongerCustomDomainWithStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestAdvanceCachePutRequest

References: apidef.CacheOptions, apidef.VersionInfo, assert.NoError, http.MethodDelete, http.MethodPatch, http.MethodPut, json.Unmarshal, storage.RedisCluster, test.TestCase, time.Millisecond.

TestAdvanceCacheTimeoutPerEndpoint

References: apidef.CacheMeta, apidef.CacheOptions, apidef.ExtendedPathsSet, apidef.VersionInfo, http.MethodGet, storage.RedisCluster, test.TestCase, time.Millisecond.

TestAllApisAreMTLS

References: apidef.APIDefinition.

TestAmIPolling

References: storage.RedisCluster.

TestAnalyticRecord_GraphStats

References: analytics.AnalyticsRecord, analytics.GraphError, analytics.OperationQuery, apidef.GraphQLConfig, apidef.GraphQLConfigVersion2, apidef.GraphQLExecutionModeProxyOnly, assert.ElementsMatch, assert.Equal, assert.False, assert.NoError, assert.True, graphql.Request, http.MethodPost, http.StatusInternalServerError, http.StatusOK, httpclient.AcceptEncodingHeader, test.TestCase, testing.T.

TestAnalyticsIgnoreSubgraph

References: analytics.AnalyticsRecord, apidef.GraphQLConfig, apidef.GraphQLConfigVersion2, apidef.GraphQLExecutionModeSubgraph, apidef.GraphQLExecutionModeSupergraph, apidef.GraphQLSubgraphConfig, apidef.GraphQLSubgraphEntity, apidef.GraphQLSupergraphConfig, assert.False, assert.NoError, graphql.Request, test.TestCase.

TestAnalytics_Write

References: analytics.AnalyticsRecord, apidef.CacheOptions, assert.Equal, assert.Len, assert.Nil, assert.NotNil, base64.StdEncoding, config.Config, http.Client, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, strings.Contains, test.Flaky, test.TestCase, testing.T, time.Millisecond, time.Sleep, user.SessionState.

TestApiHandlerPostDupPath

References: testing.T.

TestAppendIfMissingUniqueness

References: assert.Equal, strings.Split.

TestApplyLifetime

References: assert.Equal, testing.T, user.AccessDefinition, user.SessionState.

TestApplyMultiPolicies

References: assert.Equal, assert.EqualValues, assert.True, fmt.Sprintf, header.XRateLimitRemaining, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusOK, http.StatusTooManyRequests, json.Unmarshal, strconv.Itoa, test.TestCase, testing.T, time.Now, user.APILimit, user.AccessDefinition, user.Policy, user.RateLimit, user.SessionState, uuid.New.

TestApplyPoliciesQuotaAPILimit

References: fmt.Sprintf, header.XRateLimitRemaining, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusOK, json.Unmarshal, reflect.DeepEqual, test.TestCase, testing.T, user.APILimit, user.AccessDefinition, user.Policy, user.PolicyPartitions, user.RateLimit, user.SessionState, uuid.New.

TestAreMapsEqual

References: testing.T.

TestAssertNegativePS512JWT

References: assert.Error.

TestAssertPS512JWT

References: assert.NoError.

TestAssertRS256JWT

References: assert.NoError.

TestAuthCodeRedirect

References: http.Client, http.ErrUseLastResponse, http.MethodGet, http.Request, http.StatusTemporaryRedirect, strings.Contains, test.TestCase, testing.T, url.Values.

TestAuthCodeRedirectInvalidMultipleURL

References: config.Config, http.MethodPost, http.StatusForbidden, test.TestCase, testing.T, url.Values.

TestAuthCodeRedirectMultipleURL

References: config.Config, http.Client, http.ErrUseLastResponse, http.MethodPost, http.Request, http.StatusTemporaryRedirect, test.TestCase, testing.T, url.Values.

TestAuthenticationAfterDeleteKey

References: http.MethodDelete, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, user.AccessDefinition, user.SessionState.

TestAuthenticationAfterUpdateKey

References: http.StatusForbidden, http.StatusOK, storage.HashKey, test.TestCase, testing.T, user.AccessDefinition.

TestBaseMiddleware_OrgSessionExpiry

References: assert.Equal, cache.DefaultExpiration, config.Config.

TestBaseMiddleware_getAuthToken

References: apidef.APIDefinition, apidef.AuthConfig, assert.Empty, assert.Equal, http.Cookie, http.MethodGet, http.NewRequest, http.Request, testing.T.

TestBaseMiddleware_getAuthType

References: apidef.APIDefinition, apidef.AuthConfig, apidef.AuthTokenType, apidef.BasicType, apidef.CoprocessType, apidef.HMACType, apidef.JWTType, apidef.OAuthType, apidef.OIDCType, assert.Equal, http.MethodGet, http.NewRequest, http.Request.

TestBasicAuth

References: test.Flaky, test.TestCase.

TestBasicAuthCachedPasswordCollision

References: fmt.Sprintf, http.StatusOK, http.StatusUnauthorized, test.TestCase, testing.T.

TestBasicAuthCachedUserCollision

References: http.StatusOK, http.StatusUnauthorized, test.TestCase.

TestBasicAuthFromBody

References: test.TestCase, user.AccessDefinition.

TestBasicAuthHashKeyFunc

References: assert.Equal, assert.Len, assert.NoError, assert.NotEmpty, fmt.Sprintf, testing.T.

TestBasicAuthLegacyWithHashFunc

References: storage.HashMurmur64, test.TestCase.

TestBatch

References: ioutil.ReadAll, json.RawMessage, json.Unmarshal, test.TestCase.

TestBatchIgnoreCanonicalHeaderKey

References: apidef.ExtendedPathsSet, apidef.UseBlob, apidef.VersionInfo, apidef.VirtualMeta, atomic.Value, base64.StdEncoding, fasthttp.RequestCtx, fasthttp.Server, net.Listen, strings.Replace, test.TestCase.

TestBearerTokenAuthKeySession

References: httptest.NewRecorder.

TestBlacklist

References: apidef.EndPointMeta, apidef.VersionInfo, http.StatusForbidden, http.StatusOK, json.Unmarshal, test.TestCase, testing.T.

TestBodyTransformCaseSensitivity

References: apidef.ResponseProcessor, apidef.TemplateData, apidef.TemplateMeta, apidef.VersionInfo, base64.StdEncoding, test.TestCase, testing.T.

TestBrokenClients

References: analytics.AnalyticsRecord, config.Config, msgpack.Unmarshal, net.DialTimeout, testing.T, time.Millisecond, time.Sleep.

TestBuildRequest

References: header.ApplicationJSON, header.ContentType, header.TykHookshot, header.UserAgent, http.MethodGet.

TestBuildRequestIngoreCanonicalHeaderKey

References: assert.NoError, config.WebHookHandlerConf.

TestBundleFetcher

References: assert.Empty, testing.T.

TestBundleLoader

References: apidef.APIDefinition, assert.Empty, assert.Error, assert.ErrorContains, assert.NoError, config.Config, filepath.Join, fmt.Sprintf, io.WriteString, md5.New, os.CreateTemp, os.IsNotExist, os.Remove, os.Stat, pem.Block, pem.Encode, rand.Reader, rsa.GenerateKey, testing.T, x509.MarshalPKIXPublicKey.

TestBundle_Pull

References: assert.Equal, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusNotFound, httptest.NewServer, testing.T.

TestBundle_Verify

References: apidef.APIDefinition, apidef.BundleManifest, config.Config, testing.T.

TestCORS

References: http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, uuid.New.

TestCacheAllSafeRequests

References: apidef.CacheOptions, storage.RedisCluster, test.TestCase, time.Millisecond.

TestCacheAllSafeRequestsWithAdvancedCacheEndpoint

References: apidef.CacheOptions, apidef.VersionInfo, http.MethodGet, json.Unmarshal, storage.RedisCluster, test.TestCase, time.Millisecond.

TestCacheAllSafeRequestsWithCachedHeaders

References: apidef.CacheOptions, http.MethodGet, storage.RedisCluster, test.TestCase, time.Millisecond, user.SessionState.

TestCacheEtag

References: apidef.CacheOptions, http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer, storage.RedisCluster, test.TestCase, time.Millisecond.

TestCachePostRequest

References: apidef.CacheMeta, apidef.CacheOptions, apidef.VersionInfo, http.MethodPost, storage.RedisCluster, test.TestCase, time.Millisecond.

TestCacheWithAdvanceUrlRewrite

References: apidef.CacheOptions, apidef.ExtendedPathsSet, apidef.RoutingTrigger, apidef.RoutingTriggerOptions, apidef.StringRegexMap, apidef.URLRewriteMeta, http.MethodGet, http.MethodPost, storage.RedisCluster, test.TestCase, time.Millisecond.

TestCache_singleErrorResponse

References: http.HandlerFunc, http.MethodGet, http.Request, http.ResponseWriter, http.StatusInternalServerError, http.StatusOK, httptest.NewServer, test.TestCase, time.Second, time.Sleep.

TestCertificateHandlerTLS

References: assert.ElementsMatch, assert.NoError, certs.CertificateBasics, certs.GetCertIDAndChainPEM, crypto.GenCertificate, crypto.GenerateRootCertAndKey, crypto.HexSHA256, fmt.Sprintf, http.MethodGet, http.MethodPost, http.StatusOK, json.Unmarshal, net.IP, net.ParseIP, pem.Decode, pkix.Name, test.TestCase, testing.T, time.Second, x509.Certificate, x509.ParseCertificate.

TestCheckActivePollerLoop

References: storage.RedisCluster, test.Flaky.

TestCheckHeaderInRemoveList

References: bytes.Buffer, fmt.Sprintf, http.MethodGet, http.NewRequest, testing.T, texttemplate.New.

TestCheckPortWhiteList

References: config.PortRange, config.PortWhiteList, testing.T.

TestChecker_HostReporter_down_then_up

References: apidef.CheckCommand, assert.Equal, atomic.Value, context.Background, context.Context, context.WithCancel, net.Listen, net.Listener, proxyproto.Listener.

TestChecker_HostReporter_up_then_down

References: apidef.CheckCommand, assert.Equal, atomic.Value, context.Background, context.Context, context.WithCancel, net.Listen, net.Listener, proxyproto.Listener.

TestChecker_triggerSampleLimit

References: assert.Equal, atomic.Value, context.Background, context.Context, context.WithCancel, net.Listen, sync.WaitGroup, test.Flaky.

TestChecksum

TestCipherSuites

References: certs.GetCertIDAndChainPEM, config.Config, crypto.GenServerCertificate, http.Client, http.Transport, test.TestCase, testing.T, tls.Config, tls.VersionTLS12.

TestCircuitBreaker5xxs

References: apidef.VersionInfo, http.StatusBadGateway, http.StatusInternalServerError, http.StatusNotImplemented, http.StatusServiceUnavailable, json.Unmarshal, test.TestCase, testing.T.

TestCircuitBreakerEvents

References: apidef.EventHandlerTriggerConfig, apidef.TykEvent, apidef.VersionInfo, http.HandlerFunc, http.MethodPost, http.Request, http.ResponseWriter, http.StatusInternalServerError, http.StatusOK, http.StatusServiceUnavailable, httptest.NewServer, ioutil.ReadAll, json.Unmarshal, test.TestCase, time.Millisecond, time.Sleep.

TestClientAccessRequest

References: http.MethodPost, http.StatusOK, test.TestCase, testing.T, url.Values.

TestClientCertificates_WithProtocolTLS

References: assert.Equal, assert.ErrorContains, assert.NoError, certs.GetCertIDAndChainPEM, config.Config, crypto.GenServerCertificate, fmt.Sprintf, net.Listen, testing.T, tls.Config, tls.Dial, tls.X509KeyPair.

TestClientRefreshRequest

References: http.MethodPost, http.StatusOK, test.TestCase, testing.T, url.Values.

TestClientRefreshRequestDouble

References: http.MethodPost, http.StatusOK, json.NewDecoder, test.TestCase, testing.T, url.Values.

TestCoProcessMiddlewareName

References: require.Equal.

TestConcurrencyReloads

References: sync.WaitGroup, test.Racy, test.TestCase.

TestConfigureAuthAndOrgStores

References: apidef.StorageEngineCode, config.Config, context.Background, reflect.TypeOf, testing.T.

TestConflictingPaths

References: apidef.VersionInfo, http.StatusOK, json.Unmarshal, test.TestCase.

TestContainsEscapedCharacters

References: testing.T.

TestContextData

References: http.Request.

TestContextSession

References: http.Request, user.SessionState.

TestContextVarsMiddleware

References: test.TestCase.

TestContextVarsMiddlewareProcessRequest

References: cmp.Diff, http.StatusOK, httptest.NewRequest, io.Reader, reflect.DeepEqual, strings.NewReader, testing.T.

TestControlListener

References: http.StatusNotFound, http.StatusOK, test.TestCase.

TestCoprocessAPIs

References: assert.True.

TestCoprocessLog

References: assert.True, fmt.Sprintf.

TestCoprocessSystemEvent

References: apidef.TykEvent, assert.Equal, assert.True.

TestCopyAllowedURLs

References: assert.Equal, testing.T, user.AccessSpec.

TestCopyHeader_NoDuplicateCORSHeaders

References: http.Header.

TestCreateBody

References: assert.NoError, config.EventMessage, strings.Contains.

TestCreateMemConnProviderIfNeeded

References: assert.Equal, assert.Eventuallyf, context.Background, context.WithCancel, context.WithValue, http.HandlerFunc, http.MethodGet, http.NewRequest, http.Request, http.ResponseWriter, require.NoError, testing.T, time.Millisecond, time.Second.

TestCreateOAuthClient

References: http.MethodPost, http.StatusBadRequest, http.StatusOK, test.MarshalJSON, test.TestCase, testing.T, user.AccessDefinition, user.Policy.

TestCustomDomain

References: config.Config, test.NewClientLocal, test.TestCase, testing.T.

TestCustomKeysEdgeGw

References: assert.False, assert.Nil, assert.NoError, assert.True, config.Config, fmt.Sprintf, http.MethodPost, http.StatusOK, io.ReadAll, json.Unmarshal, test.TestCase, testing.T, user.AccessDefinition.

TestDeepCopyBody

References: assert.Equal, assert.Nil, assert.NotNil, assert.True, bytes.NewReader, errors.New, http.MethodPost, http.Request, httptest.NewRequest, io.ReadAll.

TestDefaultVersion

References: http.StatusForbidden, http.StatusOK, test.TestCase, testing.T.

TestDeleteAPI

References: http.MethodDelete, http.StatusNotFound, test.TestCase, testing.T.

TestDeleteOauthClient

References: http.MethodDelete, http.MethodGet, http.MethodPost, http.Response, http.StatusForbidden, http.StatusNotFound, http.StatusOK, json.NewDecoder, test.TestCase, testing.T, time.Millisecond, url.Values.

TestDeleteRawKeysWithAllowanceScope

References: assert.Equal, fmt.Sprintf, testing.T, user.AccessDefinition, user.SessionState.

TestDeleteUsingTokenID

References: assert.Equal, assert.ErrorIs, assert.Nil, assert.NoError, assert.True, config.Config, http.MethodPost, http.StatusOK, io.ReadAll, json.Unmarshal, storage.ErrKeyNotFound, test.TestCase, testing.T, user.AccessDefinition.

TestDeletionOfPoliciesThatFromAKeyDoesNotMakeTheAPIKeyless

References: assert.Nil, assert.NotNil, test.TestCase, user.AccessDefinition, user.Policy, user.SessionState.

TestDifferentDomainsIdenticalListenPaths

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestDifferentDomainsIdenticalListenPathsWithStripListenPathDisabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestDifferentDomainsIdenticalListenPathsWithStripListenPathDisabledAndStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestDifferentDomainsIdenticalListenPathsWithStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestDifferentDomainsWithOneListenPathBeingASubstringOfTheOther

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestDifferentDomainsWithOneListenPathBeingASubstringOfTheOtherWithStripListenPathDisabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestDifferentDomainsWithOneListenPathBeingASubstringOfTheOtherWithStripListenPathDisabledAndStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestDifferentDomainsWithOneListenPathBeingASubstringOfTheOtherWithStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestDisableKeyActionsByUserName

References: assert.NoError, config.Config, fmt.Sprintf, http.MethodDelete, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusNotFound, http.StatusOK, io.ReadAll, json.Unmarshal, storage.HashMurmur64, test.TestCase.

TestDynamicMTLS

References: apidef.AuthConfig, assert.NoError, certs.GenCertificate, certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, time.Now, user.AccessDefinition, user.SessionState, x509.Certificate.

TestEnforcedTimeout

References: apidef.HardTimeoutMeta, apidef.VersionInfo, http.HandlerFunc, http.MethodGet, http.Request, http.ResponseWriter, http.StatusGatewayTimeout, http.StatusOK, httptest.NewServer, test.Flaky, test.TestCase, testing.T, time.Second, time.Sleep.

TestEnsureTransport

References: assert.Equal, assert.NoError, fmt.Sprintf, testing.T, url.Parse.

TestEventCurcuitBreakerMeta_LogMessage

References: assert.Equal.

TestEventHandlerByName

TestEventKeyFailureMeta_LogMessage

References: assert.Equal.

TestExternalOAuthMiddleware_introspection

References: apidef.Introspection, apidef.Provider, assert.Equal, fmt.Sprintf, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusBadRequest, http.StatusOK, http.StatusUnauthorized, httptest.NewServer, test.TestCase, testing.T, time.Minute, time.Now.

TestExternalOAuth_JWT

References: apidef.ExternalOAuth, apidef.JWTValidation, apidef.Provider, base64.StdEncoding, http.StatusInternalServerError, http.StatusOK, http.StatusUnauthorized, test.TestCase, testing.T, time.Duration, time.Hour, time.Minute, time.Now, time.Second.

TestFuzzyFindAPI

References: assert.Equal, assert.Nil, persistentmodel.NewObjectID, testing.T.

TestGRPC_BasicAuthentication

References: certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, strings.TrimPrefix, test.TestCase, user.AccessDefinition.

TestGRPC_H2C

TestGRPC_MutualTLS

References: certs.GenCertificate, certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, strings.TrimPrefix, x509.Certificate, x509.ParseCertificate.

TestGRPC_Stream_BasicAuthentication

References: certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, test.TestCase, url.Parse, user.AccessDefinition.

TestGRPC_Stream_H2C

References: grpc.WithInsecure.

TestGRPC_Stream_MutualTLS

References: certs.GenCertificate, certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, url.Parse, x509.Certificate, x509.ParseCertificate.

TestGRPC_Stream_TokenBasedAuthentication

References: certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, ioutil.ReadAll, json.Unmarshal, test.TestCase, url.Parse, user.AccessDefinition.

TestGRPC_TLS

References: certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, strings.TrimPrefix.

TestGRPC_TokenBasedAuthentication

References: certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, ioutil.ReadAll, json.Unmarshal, strings.TrimPrefix, test.TestCase, user.AccessDefinition.

TestGatewayControlAPIMutualTLS

References: assert.ErrorContains, assert.NoError, bytes.Join, certs.GetCertIDAndChainPEM, config.CertificatesConfig, config.Config, crypto.GenCertificate, crypto.GenServerCertificate, crypto.GenerateClientCertAndKeyChain, crypto.GenerateRootCertAndKey, crypto.GenerateServerCertAndKeyChain, fmt.Sprintf, http.Client, http.MethodGet, http.NewRequest, http.StatusForbidden, http.StatusOK, http.Transport, ioutil.TempDir, os.RemoveAll, test.TestCase, testing.T, tls.X509KeyPair, url.Parse, x509.Certificate.

TestGatewayGetHostDetails

References: netutil.GetIpAddress, test.NewBufferingLogger, testing.T.

TestGatewayHealthCheck

References: http.StatusNotFound, http.StatusOK, test.TestCase, testing.T.

TestGatewayTLS

References: certs.GetCertIDAndChainPEM, config.CertData, config.Config, crypto.GenServerCertificate, filepath.Join, ioutil.TempDir, ioutil.WriteFile, os.RemoveAll, test.TestCase, testing.T.

TestGatewayTagsFilter

References: apidef.APIDefinition, assert.Len, model.MergedAPIList.

TestGateway_SyncResourcesWithReload

References: assert.Equal, assert.Error, assert.ErrorIs, assert.Greater, assert.NoError, assert.Zero, config.Config, errors.New, testing.T, time.Now, time.Second, time.Since.

TestGateway_afterConfSetup

References: assert.Equal, config.AnalyticsConfigConfig, config.Config, config.SlaveOptionsConfig, context.Background, otel.OpenTelemetry, otel.Sampling, testing.T.

TestGateway_apisByIDLen

References: assert.Equal, testing.T.

TestGateway_cacheClose

TestGateway_determineHealthStatus

References: assert.Equal, config.Config, http.StatusOK, http.StatusServiceUnavailable, testing.T.

TestGateway_evaluateHealthChecks

References: assert.Equal, config.Config, testing.T.

TestGateway_gracefulShutdown

References: config.Config, context.Background, context.CancelFunc, context.Context, context.WithTimeout, http.Server, strings.Contains, testing.T, time.Nanosecond, time.Second.

TestGateway_gracefulShutdown_ConcurrentSafety

References: config.Config, context.Background, context.WithTimeout, http.Server, sync.WaitGroup, time.Second.

TestGateway_isCriticalFailure

References: assert.Equal, config.Config, testing.T.

TestGateway_policiesByIDLen

References: assert.Equal, testing.T, user.Policy.

TestGateway_readinessHandler

References: apidef.APIDefinition, assert.Equal, assert.NotNil, config.Config, context.Background, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusMethodNotAllowed, http.StatusOK, http.StatusServiceUnavailable, httptest.NewRecorder, httptest.NewRequest, json.Unmarshal, require.NoError, storage.NewConnectionHandler, testing.T.

TestGateway_readinessHandler_Integration

References: assert.Equal, http.DefaultClient, http.Get, http.MethodPost, http.NewRequest, http.StatusMethodNotAllowed, http.StatusOK, json.NewDecoder, require.NoError, testing.T.

TestGenerateCheckerId

TestGeoIPLookup

References: analytics.GeoIPLookup.

TestGet

References: assert.NoError, config.EventMessage.

TestGetAPI_WithVersionBaseID

References: apidef.HeaderBaseAPIID, apidef.URLParamLocation, assert.NotContains, http.CanonicalHeaderKey, http.StatusOK, test.TestCase.

TestGetAccessDefinitionByAPIIDOrSession

References: apidef.APIDefinition, assert.Equal, assert.Error, assert.Nil, assert.NoError, testing.T, user.APILimit, user.AccessDefinition, user.FieldAccessDefinition, user.FieldLimits, user.RateLimit, user.SessionState.

TestGetClientTokens

References: testing.T.

TestGetCoProcessGrpcServerTargetURL

References: assert.Equal, assert.Error, assert.Nil, assert.NoError, assert.NotNil, config.Config, testing.T.

TestGetCoProcessGrpcServerTargetURLAsString

References: assert.Equal, url.Parse.

TestGetCoProcessGrpcServerTargetUrlAsString

References: assert.Equal, url.URL.

TestGetFieldValues

TestGetGroupLoginCallback

References: assert.Equal, assert.Nil, assert.True, config.Config, json.Marshal, model.GWStats, model.GroupLoginRequest, model.HostDetails, model.NodeData, testing.T.

TestGetLogEntryForRequest

References: httptest.NewRequest, logrus.Entry, logrus.Fields, logrus.WithFields.

TestGetOASAPI_WithVersionBaseID

References: apidef.HeaderBaseAPIID, apidef.URLParamLocation, assert.NotContains, http.CanonicalHeaderKey, http.StatusOK, oas.OAS, openapi3.Info, openapi3.Paths, openapi3.T, test.TestCase.

TestGetOAuthClients

References: test.MarshalJSON, test.TestCase.

TestGetPaginatedClientTokens

References: config.Config, fmt.Sprintf, http.MethodGet, http.MethodPost, http.StatusOK, json.NewDecoder, test.TestCase, testing.T, url.Values, uuid.New.

TestGetRawKey

References: assert.Equal, assert.Nil, assert.NotNil, config.Config, rpc.SetEmergencyMode, storage.ErrMDCBConnectionLost, testing.T.

TestGetScopeFromClaim

References: fmt.Sprintf, testing.T.

TestGetSecretFromJWKOrConfig

References: apidef.ExternalOAuth, apidef.JWTValidation, apidef.Provider, assert.Equal, assert.Error, assert.ErrorIs, assert.NoError, base64.StdEncoding, testing.T.

TestGetSecretFromMultipleJWKURIs

References: apidef.APIDefinition, apidef.JWK, assert.Contains, assert.Equal, assert.Error, assert.NoError, cache.DefaultExpiration, config.Config, errors.New, testing.T.

TestGetUserIDFromClaim

References: assert.Equal, assert.ErrorIs, assert.NoError, fmt.Sprintf, testing.T.

TestGetVersionFromRequest

References: apidef.DefaultAPIVersionKey, apidef.HeaderLocation, apidef.URLLocation, apidef.URLParamLocation, apidef.VersionInfo, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T.

TestGlobalResponseHeaders

References: apidef.VersionInfo, test.TestCase, testing.T.

TestGoAnalyticsPlugin

References: http.StatusOK, test.TestCase, testing.T.

TestGoPluginMiddleware_EnabledForSpec

References: apidef.APIDefinition, apidef.ExtendedPathsSet, apidef.GoPluginMeta, apidef.VersionInfo, assert.False, assert.True, testing.T.

TestGranularAccessMiddleware_ProcessRequest

References: config.Config, header.Authorization, http.MethodGet, http.MethodPost, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, user.AccessDefinition, user.AccessSpec, user.Policy, user.SessionState.

TestGraphQLComplexityMiddleware_DepthLimitEnabled

References: assert.False, assert.True, logrus.NewEntry, testing.T, user.APILimit, user.AccessDefinition, user.FieldAccessDefinition, user.FieldLimits.

TestGraphQLComplexityMiddleware_DepthLimitExceeded

References: assert.Equal, graphql.NewSchemaFromString, graphql.Request, logrus.NewEntry, require.NoError, testing.T, user.APILimit, user.AccessDefinition, user.FieldAccessDefinition, user.FieldLimits.

TestGraphQLComplexityMiddleware_ProcessRequest_GraphqlLimits

References: assert.Equal, graphql.Request, http.Request, http.StatusForbidden, http.StatusInternalServerError, http.StatusOK, testing.T, user.APILimit, user.AccessDefinition, user.FieldAccessDefinition, user.FieldLimits, user.NewSessionState.

TestGraphQLMiddleware_EngineMode

References: apidef.GraphQLConfigVersion2, apidef.GraphQLConfigVersion3Preview, apidef.GraphQLEngineDataSource, apidef.GraphQLEngineDataSourceKindGraphQL, apidef.GraphQLExecutionModeExecutionEngine, apidef.GraphQLExecutionModeProxyOnly, apidef.GraphQLExecutionModeSubgraph, apidef.GraphQLExecutionModeSupergraph, apidef.GraphQLTypeFields, apidef.RequestHeadersRewriteConfig, apidef.UDGGlobalHeader, assert.Contains, assert.Equal, assert.Greater, assert.NoError, bytes.Equal, fmt.Sprintf, gql.Request, gql.Type, gqlwebsocket.ProtocolGraphQLTransportWS, gqlwebsocket.ProtocolGraphQLWS, header.Authorization, header.Connection, header.SecWebSocketKey, header.SecWebSocketProtocol, header.SecWebSocketVersion, header.Upgrade, http.HandlerFunc, http.Header, http.MethodPost, http.MethodPut, http.Request, http.ResponseWriter, http.StatusBadRequest, http.StatusInternalServerError, http.StatusOK, http.StatusUnprocessableEntity, httptest.NewServer, json.Marshal, json.RawMessage, json.Unmarshal, jsonparser.Get, require.Equal, require.NoError, strings.Replace, sync.WaitGroup, test.TestCase, testing.T, user.APILimit, user.AccessDefinition, user.SessionState, websocket.BinaryMessage, websocket.DefaultDialer.

TestGraphQLMiddleware_RequestValidation

References: apidef.GraphQLConfigVersion2, apidef.GraphQLConfigVersionNone, apidef.GraphQLExecutionModeProxyOnly, assert.NoError, config.Config, gql.ErrEmptyRequest, gql.Request, header.Authorization, http.MethodPost, http.StatusBadRequest, http.StatusForbidden, http.StatusInternalServerError, http.StatusOK, strings.Contains, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState.

TestGraphQLPersist_TransformResponse

References: apidef.ExtendedPathsSet, apidef.PersistGraphQLMeta, apidef.RequestJSON, apidef.TemplateData, apidef.TemplateMeta, apidef.UseBlob, apidef.VersionInfo, assert.NoError, base64.StdEncoding, bytes.Equal, http.MethodGet, test.TestCase.

TestGraphQLPersist_VariablesListenPath

References: apidef.ExtendedPathsSet, apidef.PersistGraphQLMeta, apidef.VersionInfo, assert.NoError, json.Unmarshal, test.TestCase.

TestGraphQLPlayground

References: assert.Contains, fmt.Sprintf, http.MethodPost, http.StatusBadRequest, http.StatusOK, path.Join, test.TestCase, testing.T.

TestGraphQL_AllowedTypes

References: assert.Contains, graphql.Request, graphql.Type, header.Authorization, http.StatusBadRequest, http.StatusOK, test.Flaky, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState.

TestGraphQL_AllowedTypes_Override_RestrictedTypes

References: assert.Contains, graphql.Request, graphql.Type, header.Authorization, http.StatusBadRequest, http.StatusOK, test.Flaky, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState.

TestGraphQL_DisableIntrospection

References: assert.Contains, graphql.Request, header.Authorization, http.StatusForbidden, http.StatusOK, test.Flaky, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState.

TestGraphQL_InternalDataSource

References: apidef.GraphQLConfig, apidef.GraphQLConfigVersion2, apidef.GraphQLEngineDataSource, apidef.GraphQLEngineDataSourceConfigGraphQL, apidef.GraphQLEngineDataSourceConfigREST, apidef.GraphQLExecutionModeExecutionEngine, apidef.GraphQLExecutionModeSubgraph, apidef.GraphQLExecutionModeSupergraph, apidef.GraphQLSubgraphConfig, apidef.GraphQLSubgraphEntity, apidef.GraphQLSupergraphConfig, datasource.GraphQLDataSourceConfig, datasource.HttpJsonDataSourceConfig, fmt.Sprintf, graphql.Request, http.StatusOK, test.TestCase, testing.T.

TestGraphQL_InternalDataSource_memConnProviders

References: apidef.GraphQLConfig, apidef.GraphQLConfigVersion2, apidef.GraphQLExecutionModeSubgraph, apidef.GraphQLExecutionModeSupergraph, apidef.GraphQLSubgraphConfig, apidef.GraphQLSubgraphEntity, apidef.GraphQLSupergraphConfig, fmt.Sprintf, graphql.Request, http.StatusOK, mathrand.Intn, require.Contains, require.NotContains, test.TestCase, time.Minute, time.Now.

TestGraphQL_OptionsPassThrough

References: apidef.CORSConfig, apidef.GraphQLExecutionModeExecutionEngine, apidef.GraphQLExecutionModeProxyOnly, http.MethodOptions, http.MethodPost, http.StatusInternalServerError, http.StatusOK, test.TestCase, testing.T.

TestGraphQL_ProxyIntrospectionInterrupt

References: apidef.GraphQLExecutionModeProxyOnly, graphql.Request, http.StatusOK, strings.Replace, test.TestCase, testing.T.

TestGraphQL_ProxyOnlyHeaders

References: apidef.GraphQLConfigVersion2, apidef.GraphQLExecutionModeProxyOnly, assert.NoError, graphql.Request, http.MethodPost, http.Request, http.ResponseWriter, test.TestCase, testing.T.

TestGraphQL_ProxyOnlyPassHeadersWithOTel

References: apidef.GraphQLConfigVersion2, apidef.GraphQLExecutionModeProxyOnly, assert.NoError, config.Config, graphql.Request, http.MethodPost, http.Request, http.ResponseWriter, test.TestCase.

TestGraphQL_RestrictedTypes

References: assert.Contains, graphql.Request, graphql.Type, header.Authorization, http.StatusBadRequest, http.StatusOK, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState.

TestGraphQL_SubgraphBatchRequest

References: apidef.GraphQLConfig, apidef.GraphQLConfigVersion2, apidef.GraphQLExecutionModeSubgraph, apidef.GraphQLExecutionModeSupergraph, apidef.GraphQLSubgraphConfig, apidef.GraphQLSubgraphEntity, apidef.GraphQLSupergraphConfig, assert.Eventually, assert.Fail, context.Background, context.WithCancel, graphql.Request, http.Request, http.ResponseWriter, sync.Mutex, test.TestCase, testing.T, time.Millisecond, time.Second.

TestGraphQL_UDGHeaders

References: apidef.GraphQLConfigVersion2, apidef.GraphQLEngineDataSource, apidef.GraphQLEngineDataSourceConfigREST, apidef.GraphQLExecutionModeExecutionEngine, apidef.UDGGlobalHeader, graphql.Request, http.StatusOK, json.Unmarshal, require.NoError, strings.Contains, test.TestCase.

TestGraphqlPersist_MatchPathInfo

References: apidef.ExtendedPathsSet, apidef.PersistGraphQLMeta, apidef.VersionInfo, assert.NoError, json.Marshal, json.Unmarshal, test.TestCase.

TestGraphqlPersist_MultipleVersions

References: apidef.ExtendedPathsSet, apidef.PersistGraphQLMeta, apidef.VersionInfo, assert.NoError, json.Marshal, json.RawMessage, json.Unmarshal, test.TestCase.

TestGraphqlPersist_Variables

References: apidef.ExtendedPathsSet, apidef.PersistGraphQLMeta, apidef.VersionInfo, assert.NoError, json.Unmarshal, test.TestCase.

TestGroupResetHandler

References: assert.Equal, assert.Fail, assert.NoError, assert.True, context.WithTimeout, http.StatusOK, httptest.NewRecorder, json.Unmarshal, require.Len, require.NoError, require.True, storage.RedisCluster, sync.WaitGroup, temporalmodel.Message, temporalmodel.MessageTypeMessage, temporalmodel.MessageTypeSubscription, time.Second.

TestHMACAuthSessionAuxDateHeader

References: apidef.TykEvent, base64.StdEncoding, config.EventMessage, config.TykEventHandler, fmt.Sprintf, hmac.New, httptest.NewRecorder, sha1.New, strings.ToLower, sync.WaitGroup, time.Millisecond, time.Now, url.QueryEscape.

TestHMACAuthSessionFailureDateExpired

References: apidef.TykEvent, base64.StdEncoding, config.EventMessage, config.TykEventHandler, fmt.Sprintf, hmac.New, httptest.NewRecorder, sha1.New, strings.ToLower, sync.WaitGroup, time.Millisecond, time.Now, url.QueryEscape.

TestHMACAuthSessionKeyMissing

References: apidef.TykEvent, base64.StdEncoding, config.EventMessage, config.TykEventHandler, fmt.Sprintf, hmac.New, httptest.NewRecorder, sha1.New, strings.ToLower, sync.WaitGroup, time.Millisecond, time.Now, url.QueryEscape.

TestHMACAuthSessionMalformedHeader

References: apidef.TykEvent, base64.StdEncoding, config.EventMessage, config.TykEventHandler, fmt.Sprintf, hmac.New, httptest.NewRecorder, sha1.New, strings.ToLower, sync.WaitGroup, time.Millisecond, time.Now, url.QueryEscape.

TestHMACAuthSessionPass

References: fmt.Sprintf, httptest.NewRecorder, sha1.New, sync.WaitGroup, time.Millisecond.

TestHMACAuthSessionPassWithHeaderField

References: fmt.Sprintf, httptest.NewRecorder, sha1.New, sync.WaitGroup, time.Millisecond.

TestHMACAuthSessionPassWithHeaderFieldLowerCase

References: apidef.TykEvent, base64.StdEncoding, config.EventMessage, config.TykEventHandler, fmt.Sprintf, hmac.New, httptest.NewRecorder, sha1.New, strings.ToLower, sync.WaitGroup, time.Millisecond, time.Now, url.QueryEscape.

TestHMACAuthSessionSHA512Pass

References: fmt.Sprintf, httptest.NewRecorder, sha512.New, sync.WaitGroup, time.Millisecond.

TestHMACRequestSigning

References: apidef.AuthConfig, httptest.NewRecorder, testing.T, time.Now.

TestHTTP2_TLS

References: certs.GenCertificate, certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, fmt.Fprintln, http.HandlerFunc, http.Request, http.ResponseWriter, http.Transport, http2.ConfigureTransport, httptest.NewUnstartedServer, test.TestCase, tls.Config, x509.Certificate.

TestHTTP2_h2C

References: fmt.Sprintf, h2c.NewHandler, http.Client, http.HandlerFunc, http.Request, http.ResponseWriter, http2.Server, http2.Transport, httptest.NewUnstartedServer, ioutil.ReadAll, net.Conn, net.Dial, strings.Replace, tls.Config.

TestHTTP_custom_ports

References: fmt.Sprintf, http.Get, http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer, ioutil.ReadAll.

TestHandle404

References: http.StatusNotFound, http.StatusOK, http.StatusText, test.TestCase.

TestHandleAddApi

References: afero.NewMemMapFs, apidef.DummyAPI, apidef.GraphQLEngineDataSource, assert.Equal, assert.NotEmpty, bytes.NewBuffer, http.MethodPost, http.NewRequest, http.StatusBadRequest, http.StatusOK, json.Marshal, require.NoError, require.True, testing.T.

TestHandleAddApi_AddVersionAtomically

References: apidef.APIDefinition, apidef.DefaultAPIVersionKey, apidef.HeaderLocation, assert.Equal, assert.Len, assert.NoError, assert.True, fmt.Sprintf, http.MethodGet, http.MethodPost, http.StatusOK, json.Unmarshal, test.TestCase.

TestHandleAddOASApi_AddVersionAtomically

References: apidef.DefaultAPIVersionKey, apidef.HeaderLocation, assert.Equal, assert.Len, assert.NoError, assert.True, fmt.Sprintf, http.MethodGet, http.MethodPost, http.StatusOK, json.Unmarshal, oas.OAS, oas.VersionToID, openapi3.Info, openapi3.Paths, openapi3.T, test.TestCase.

TestHandleDefaultErrorJSON

References: bytes.TrimSpace, header.ApplicationJSON, header.ContentType, http.StatusInternalServerError, strings.TrimSpace, test.TestCase.

TestHandleDefaultErrorXml

References: bytes.TrimSpace, header.ContentType, header.TextXML, http.StatusInternalServerError, strings.TrimSpace, test.TestCase.

TestHandleDeleteAPI_RemoveVersionAtomically

References: apidef.APIDefinition, assert.Equal, assert.NoError, http.MethodDelete, http.MethodPost, http.StatusNotFound, http.StatusOK, json.Unmarshal, test.TestCase.

TestHandleDeleteOASAPI_RemoveVersionAtomically

References: apidef.DefaultAPIVersionKey, apidef.HeaderLocation, assert.Equal, assert.NoError, http.MethodDelete, http.MethodPost, http.StatusNotFound, http.StatusOK, json.Unmarshal, oas.OAS, oas.VersionToID, openapi3.Info, openapi3.Paths, openapi3.T, test.TestCase.

TestHandleListAPIVersions

References: apidef.URLParamLocation, assert.Equal, assert.False, assert.Len, assert.NoError, assert.True, fmt.Sprintf, http.MethodGet, json.Unmarshal, oas.OAS, oas.VersionToID, oas.Versioning, test.TestCase, testing.T.

TestHandleSubroutes

References: config.Config, http.StatusNotFound, http.StatusOK, http.StatusText, http.StatusUnauthorized, test.TestCase.

TestHandleUpdateApi

References: afero.NewMemMapFs, apidef.DummyAPI, apidef.GraphQLEngineDataSource, assert.Equal, bytes.NewBuffer, http.MethodPost, http.MethodPut, http.NewRequest, http.StatusBadRequest, http.StatusNotFound, http.StatusOK, json.Marshal, require.NoError, require.True, test.TestCase, testing.T.

TestHandleUserKeyReset

References: assert.Equal, fmt.Sprintf, testing.T.

TestHashKeyFunctionChanged

References: apidef.AuthConfig, apidef.AuthTokenType, certs.GenCertificate, certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, header.Authorization, http.Client, http.MethodPost, http.StatusForbidden, http.StatusOK, http.StatusUnauthorized, test.TestCase, testing.T, user.AccessDefinition, x509.Certificate.

TestHashKeyHandler

References: assert.True, config.Config, fmt.Sprintf, storage.HashMurmur128, storage.HashMurmur32, storage.HashMurmur64, storage.HashSha256, testing.T.

TestHashKeyHandlerLegacyWithHashFunc

References: storage.HashMurmur64, test.Racy, test.TestCase.

TestHashKeyListingDisabled

References: fmt.Sprintf, storage.HashKey, test.MarshalJSON, test.TestCase, testing.T, user.AccessDefinition, uuid.New.

TestHeaderInjectionMeta_Enabled

References: apidef.HeaderInjectionMeta, assert.False, assert.True.

TestHeaderInjector_Enabled

References: apidef.APIDefinition, apidef.HeaderInjectionMeta, apidef.VersionInfo, assert.False, assert.True.

TestHeaderTransformBase

References: require.Equal.

TestHealthCheckEndpoint

References: test.TestCase.

TestHostChecker

References: apidef.NewHostListFromList, apidef.TykEvent, bytes.Buffer, config.Config, config.EventMessage, config.TykEventHandler, storage.RedisCluster, sync.WaitGroup, texttemplate.Must, texttemplate.New, uuid.New.

TestHostCheckerManagerInit

References: storage.RedisCluster.

TestHotReloadSingle

References: sync.WaitGroup.

TestHttpPprof

References: config.Config, test.TestCase, testing.T.

TestIDExtractorDisabled

References: apidef.HeaderSource, apidef.ValueExtractor, assert.Nil.

TestIPBlackListMiddleware_EnabledForSpec

References: apidef.APIDefinition, assert.Equal, testing.T.

TestIPBlacklistMiddleware

References: header.XRealIP, httptest.NewRecorder.

TestIPMiddlewarePass

References: header.XRealIP, httptest.NewRecorder.

TestIPWhiteListMiddleware_EnabledForSpec

References: apidef.APIDefinition, assert.Equal, testing.T.

TestIdenticalDomains

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestIdenticalDomainsWithRegex

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestIdenticalDomainsWithRegexWithStripListenPathDisabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestIdenticalDomainsWithRegexWithStripListenPathDisabledAndStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestIdenticalDomainsWithRegexWithStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestIdenticalDomainsWithStripListenPathDisabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestIdenticalDomainsWithStripListenPathDisabledAndStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestIdenticalDomainsWithStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestIgnored

References: apidef.EndPointMeta, apidef.EndpointMethodMeta, apidef.NoAction, apidef.URLRewriteMeta, apidef.VersionInfo, config.Config, http.MethodGet, http.StatusOK, http.StatusUnauthorized, json.Unmarshal, test.TestCase, testing.T.

TestInitGenericEventHandlers

References: apidef.TykEvent, config.Config.

TestInitTriggerRx

References: apidef.APIDefinition, apidef.ExtendedPathsSet, apidef.RoutingTrigger, apidef.RoutingTriggerOptions, apidef.StringRegexMap, apidef.URLRewriteMeta, apidef.VersionInfo.

TestInternalAPIUsage

References: fmt.Sprintf, http.StatusOK, test.TestCase, testing.T.

TestInternalEndpointMW_TT_11126

References: apidef.VersionInfo, assert.NoError, http.StatusForbidden, json.Unmarshal, test.TestCase.

TestInvalidateCache

References: test.TestCase.

TestIsGraphQLProxyOnly

References: apidef.APIDefinition, apidef.GraphQLConfig, apidef.GraphQLExecutionMode, apidef.GraphQLExecutionModeExecutionEngine, apidef.GraphQLExecutionModeProxyOnly, apidef.GraphQLExecutionModeSubgraph, apidef.GraphQLExecutionModeSupergraph, assert.Equal, testing.T.

TestJSONToFormValues

References: bytes.NewReader, http.MethodPost, http.NewRequest, test.MarshalJSON, testing.T.

TestJSVMBase64

References: logrus.NewEntry, testing.T.

TestJSVMBody

References: apidef.APIDefinition, assert.Equal, httptest.NewRequest, ioutil.ReadAll, logrus.NewEntry, strings.NewReader, testing.T.

TestJSVMConfigData

References: apidef.APIDefinition, assert.Empty, assert.Equal, logrus.NewEntry, testing.T.

TestJSVMEventHandler_Init

References: assert.Equal, assert.ErrorIs, assert.NoError, testing.T.

TestJSVMLogs

References: bytes.Buffer, logger.RawFormatter, logrus.New, logrus.NewEntry, regexp.MustCompile, strings.Contains, strings.Split, strings.Trim.

TestJSVMProcessTimeout

References: apidef.APIDefinition, httptest.NewRequest, logrus.NewEntry, strings.NewReader, time.After, time.Millisecond, time.Second.

TestJSVMRequestScheme

References: apidef.APIDefinition, httptest.NewRequest, ioutil.ReadAll, logrus.NewEntry.

TestJSVMSessionMetadataUpdate

References: apidef.APIDefinition, ctx.GetSession, httptest.NewRequest, logrus.NewEntry, user.SessionState.

TestJSVMStagesRequest

References: apidef.MiddlewareDefinition, apidef.MiddlewareSection, apidef.OttoDriver, http.StatusOK, test.TestCase, testing.T.

TestJSVMUserCore

References: apidef.APIDefinition, io.WriteString, ioutil.TempFile, logrus.NewEntry.

TestJSVM_Auth

References: fmt.Sprintf, testing.T.

TestJSVM_IgnoreCanonicalHeader

References: apidef.APIDefinition, logrus.NewEntry.

TestJSVM_MultiAuthentication

References: apidef.AuthToken, apidef.AuthTypeEnum, apidef.CustomAuth, apidef.OttoDriver, apidef.VersionInfo, assert.Equal, assert.True, fmt.Sprintf, http.StatusOK, test.TestCase, testing.T, user.AccessDefinition, user.SessionState.

TestJSVM_StopProxyWhenFail

References: apidef.MiddlewareDefinition, apidef.OttoDriver, http.StatusInternalServerError, http.StatusText, logrus.NewEntry, test.TestCase, testing.T.

TestJWTAuthKeyMultiAuth

References: apidef.AuthConfig, apidef.AuthToken, base64.StdEncoding, http.StatusBadRequest, http.StatusForbidden, http.StatusOK, http.StatusUnauthorized, test.TestCase, time.Hour, time.Now, user.AccessDefinition, user.Policy.

TestJWTDefaultPolicies

References: base64.StdEncoding, fmt.Sprintf, http.StatusForbidden, http.StatusOK, md5.Sum, reflect.DeepEqual, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.PolicyPartitions.

TestJWTECDSASign

References: http.StatusOK, test.TestCase, testing.T.

TestJWTExistingSessionRSAWithRawSourceInvalidPolicyID

References: base64.StdEncoding, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, time.Hour, time.Now, user.AccessDefinition, user.Policy, uuid.New.

TestJWTExistingSessionRSAWithRawSourcePolicyIDChanged

References: base64.StdEncoding, fmt.Sprintf, http.MethodGet, http.StatusOK, md5.Sum, test.TestCase, testing.T, time.Hour, time.Now, user.AccessDefinition, user.Policy, uuid.New.

TestJWTExpOverride

References: base64.StdEncoding, http.StatusOK, http.StatusUnauthorized, test.Flaky, test.TestCase, testing.T, time.Millisecond, time.Now, time.Second, user.AccessDefinition, user.Policy, uuid.New.

TestJWTHMACIdInSubClaim

References: http.StatusForbidden, http.StatusOK, test.TestCase, testing.T.

TestJWTHMACIdNewClaim

References: http.StatusOK, test.TestCase, testing.T.

TestJWTMiddleware_getSecretToVerifySignature_JWKNoKID

References: apidef.APIDefinition, apidef.JWK, assert.Error, assert.ErrorIs, base64.StdEncoding, testing.T.

TestJWTRSAIdInClaimsWithBaseField

References: base64.StdEncoding, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, time.Hour, time.Now, user.AccessDefinition, user.Policy.

TestJWTRSAIdInClaimsWithoutBaseField

References: base64.StdEncoding, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, time.Hour, time.Now, user.AccessDefinition, user.Policy.

TestJWTRSAIdInSubClaim

References: http.StatusForbidden, http.StatusOK, test.TestCase, testing.T.

TestJWTRSAInvalidPublickKey

References: base64.StdEncoding, http.StatusForbidden, test.TestCase, testing.T, time.Hour, time.Now.

TestJWTScopeToPolicyMapping

References: apidef.ScopeClaim, apidef.Scopes, assert.Equal, base64.StdEncoding, fmt.Sprintf, http.MethodGet, http.StatusForbidden, http.StatusOK, json.Unmarshal, md5.Sum, sort.Strings, test.TestCase, testing.T, time.Hour, time.Now, user.APILimit, user.AccessDefinition, user.Policy, user.PolicyPartitions, user.RateLimit, user.SessionState, uuid.New.

TestJWTSessionExpiresAtValidationConfigs

References: base64.StdEncoding, http.StatusOK, http.StatusUnauthorized, test.TestCase, testing.T, time.Duration, time.Now, time.Second, user.AccessDefinition, user.Policy.

TestJWTSessionFailRSA_EmptyJWT

References: test.TestCase, testing.T.

TestJWTSessionFailRSA_MalformedJWT

References: http.StatusForbidden, test.TestCase, testing.T.

TestJWTSessionFailRSA_MalformedJWT_NOTRACK

References: http.StatusForbidden, test.TestCase, testing.T.

TestJWTSessionFailRSA_NoAuthHeader

References: http.StatusBadRequest, test.TestCase, testing.T.

TestJWTSessionFailRSA_WrongJWT

References: http.StatusForbidden, test.TestCase, testing.T.

TestJWTSessionFailRSA_WrongJWT_Signature

References: http.StatusForbidden, test.TestCase, testing.T.

TestJWTSessionHMAC

References: http.StatusOK, test.TestCase, testing.T.

TestJWTSessionIssueAtValidationConfigs

References: base64.StdEncoding, http.StatusOK, http.StatusUnauthorized, test.TestCase, testing.T, time.Duration, time.Minute, time.Now, time.Second, user.AccessDefinition, user.Policy.

TestJWTSessionNotBeforeValidationConfigs

References: base64.StdEncoding, http.StatusOK, http.StatusUnauthorized, test.Flaky, test.TestCase, testing.T, time.Duration, time.Now, time.Second, user.AccessDefinition, user.Policy.

TestJWTSessionRSA

References: http.StatusOK, test.TestCase, testing.T.

TestJWTSessionRSABearer

References: http.StatusOK, test.TestCase, testing.T.

TestJWTSessionRSABearerInvalid

References: http.StatusForbidden, test.TestCase, testing.T.

TestJWTSessionRSABearerInvalidTwoBears

References: http.StatusForbidden, test.TestCase, testing.T.

TestJWTSessionRSAWithEncodedJWK

References: base64.StdEncoding, http.StatusOK, test.TestCase, testing.T.

TestJWTSessionRSAWithJWK

References: http.StatusOK, test.TestCase, testing.T.

TestJWTSessionRSAWithRawSource

References: http.StatusOK, test.TestCase, testing.T.

TestJWTSessionRSAWithRawSourceInvalidPolicyID

References: base64.StdEncoding, http.StatusForbidden, test.TestCase, testing.T, time.Hour, time.Now.

TestJWTSessionRSAWithRawSourceOnWithClientID

References: http.StatusOK, test.TestCase, testing.T.

TestJWTUnknownSign

References: http.StatusOK, test.TestCase, testing.T.

TestJWT_ExtractOAuthClientIDForDCR

References: assert.Empty, assert.Equal, assert.True, base64.StdEncoding, fmt.Sprintf, http.StatusOK, md5.Sum, test.TestCase, testing.T, time.Now, time.Second, user.AccessDefinition, user.Policy, uuid.New.

TestKeepAliveConns

References: test.TestCase, testing.T, time.Minute, time.Now.

TestKeyHandler

References: http.Response, json.NewDecoder, reflect.DeepEqual, sort.Strings, test.MarshalJSON, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState, uuid.New.

TestKeyHandler_CheckKeysNotDuplicateOnUpdate

References: bytes.NewReader, http.MethodPut, httptest.NewRequest, test.MarshalJSON, testing.T, user.AccessDefinition.

TestKeyHandler_DeleteKeyWithQuota

References: assert.Equal, config.Config, storage.HashKey, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState.

TestKeyHandler_HashingDisabled

References: fmt.Sprintf, storage.HashKey, test.MarshalJSON, test.Racy, test.TestCase, testing.T, user.AccessDefinition, uuid.New.

TestKeyHandler_UpdateKey

References: fmt.Sprintf, http.MethodPut, reflect.DeepEqual, sort.Strings, test.MarshalJSON, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState.

TestKeyWithCertificateTLS

References: apidef.AuthConfig, apidef.AuthToken, apidef.AuthTokenType, certs.GetCertIDAndChainPEM, config.Config, crypto.GenCertificate, crypto.GenServerCertificate, header.Authorization, http.Client, http.StatusForbidden, http.StatusNotFound, http.StatusOK, http.Transport, storage.HashKey, test.Flaky, test.NewTransport, test.TestCase, test.WithLocalDialer, testing.T, tls.Config, user.AccessDefinition, user.SessionState, x509.Certificate.

TestLegacyHeaderInjectorWithResponseProcessorOptions

References: apidef.ResponseProcessor, test.TestCase.

TestListenPathTykPrefix

References: test.TestCase.

TestListener

References: test.TestCase.

TestListenerWithStrictRoutes

References: config.Config, test.TestCase.

TestLoadPlugin

References: assert.Equal.

TestLoadPoliciesFromDashboardReLogin

References: assert.Empty, assert.Error, config.Config, http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer.

TestLogMessageEventHandler

References: bytes.Buffer, config.EventMessage, logrus.New, strings.Contains, time.Now.

TestLogMessageEventHandler_Init

References: assert.Equal, assert.ErrorIs, assert.NoError, testing.T.

TestLongerListenPathHasLongerDomainThanSubstringListenPath

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestLongerListenPathHasLongerDomainThanSubstringListenPathWithStripListenPathDisabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestLongerListenPathHasLongerDomainThanSubstringListenPathWithStripListenPathDisabledAndStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestLongerListenPathHasLongerDomainThanSubstringListenPathWithStripSlashEnabled

References: http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, test.NewClientLocal, test.TestCase, testing.T.

TestLooping

References: apidef.APIDefinition, json.Unmarshal, oas.Info, oas.ListenPath, oas.OAS, oas.Server, oas.State, oas.Upstream, oas.XTykAPIGateway, openapi3.Info, openapi3.Paths, openapi3.T, test.Flaky, test.TestCase, testing.T, user.SessionState.

TestLoopingUrl

References: assert.Equal, testing.T.

TestLooping_AnotherAPIWithAuthTokens

References: apidef.AuthConfig, apidef.URLRewriteMeta, apidef.VersionInfo, http.MethodGet, http.StatusForbidden, http.StatusOK, http.StatusUnauthorized, test.TestCase, user.AccessDefinition, user.SessionState.

TestMain

References: context.Background, os.Exit.

TestManagementNodeRedisEvents

References: json.Marshal, test.MarshalJSON, testing.T.

TestMethodTransform

References: apidef.CacheOptions, apidef.MethodTransformMeta, apidef.URLRewriteMeta, apidef.VersionInfo, http.MethodGet, http.MethodPost, test.TestCase, testing.T.

TestMiniRequestObject_ReconstructParams

References: assert.Equal, http.MethodGet, http.NewRequest, testing.T, url.Values.

TestMockResponse

References: assert.NoError, context.Background, http.StatusOK, http.StatusTeapot, http.StatusUnauthorized, oas.FromOASExamples, oas.Header, oas.Middleware, oas.MockResponse, oas.OAS, oas.Operations, oas.XTykAPIGateway, openapi3.Content, openapi3.Example, openapi3.ExampleRef, openapi3.Examples, openapi3.Info, openapi3.MediaType, openapi3.NewResponses, openapi3.Operation, openapi3.Paths, openapi3.Response, openapi3.ResponseRef, test.TestCase, testing.T.

TestMultiAuthBackwardsCompatibleSession

References: fmt.Sprintf, httptest.NewRecorder.

TestMultiAuthSession

References: fmt.Sprintf, http.Cookie, httptest.NewRecorder.

TestMultiSession_BA_Standard_FailBA

References: base64.StdEncoding, fmt.Sprintf, httptest.NewRecorder, strings.Join.

TestMultiSession_BA_Standard_FailStandard

References: base64.StdEncoding, fmt.Sprintf, httptest.NewRecorder, strings.Join.

TestMultiSession_BA_Standard_Identity

References: base64.StdEncoding, fmt.Sprintf, httptest.NewRecorder, strings.Join.

TestMultiSession_BA_Standard_OK

References: httptest.NewRecorder.

TestMultiTargetProxy

References: apidef.VersionInfo, test.TestCase.

TestMurmur3CharBug

References: test.TestCase, testing.T.

TestMwRateLimiting_CustomRatelimitKeyDRL

TestMwRateLimiting_CustomRatelimitKeyNonTransactional

TestMwRateLimiting_CustomRatelimitKeyRedis

TestMwRateLimiting_CustomRatelimitKeySentinel

TestMwRateLimiting_DepthLimit

References: assert.Equal, graphql.Request, header.Authorization, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, user.APILimit, user.AccessDefinition, user.FieldAccessDefinition, user.FieldLimits, user.SessionState.

TestNeedsGraphQLExecutionEngine

References: apidef.APIDefinition, apidef.GraphQLConfig, apidef.GraphQLConfigVersion, apidef.GraphQLConfigVersion1, apidef.GraphQLConfigVersion2, apidef.GraphQLExecutionMode, apidef.GraphQLExecutionModeExecutionEngine, apidef.GraphQLExecutionModeProxyOnly, apidef.GraphQLExecutionModeSupergraph, assert.Equal, testing.T.

TestNeverRenewQuota

References: header.Authorization, http.StatusForbidden, http.StatusOK, test.TestCase, user.APILimit, user.AccessDefinition, user.SessionState.

TestNewCustomTemplate

References: testing.T.

TestNewInvalid

TestNewMockResponse

References: apidef.MockResponseMeta, apidef.VersionInfo, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusInsufficientStorage, http.StatusOK, http.StatusTeapot, test.TestCase, testing.T.

TestNewValid

References: assert.ErrorIs, assert.False, assert.NoError, assert.True, testing.T.

TestNewVersioning

References: apidef.Self, apidef.URLParamLocation, http.StatusForbidden, http.StatusNotFound, http.StatusOK, http.StatusUnauthorized, test.TestCase, testing.T, user.AccessDefinition, user.SessionState.

TestNopCloseRequestBody

References: assert.Nil, bytes.Equal, http.MethodGet, http.Request, httptest.NewRequest, ioutil.ReadAll, strings.NewReader.

TestNopCloseResponseBody

References: assert.Nil, bytes.Equal, http.Response, ioutil.NopCloser, ioutil.ReadAll, strings.NewReader.

TestNotVersioned

References: apidef.VersionInfo, http.StatusInternalServerError, http.StatusOK, test.TestCase, testing.T.

TestOAS

References: apidef.ErrAPINotFound, apidef.ErrAPINotMigrated, apidef.ErrClassicAPIExpected, apidef.ErrImportWithTykExtension, apidef.ErrOASGetForOldAPI, apidef.ErrPayloadWithoutTykExtension, assert.Equal, assert.EqualValues, assert.Error, assert.False, assert.NoError, assert.NotNil, assert.True, filepath.Join, fmt.Sprintf, http.MethodDelete, http.MethodGet, http.MethodPatch, http.MethodPost, http.MethodPut, http.StatusBadRequest, http.StatusInternalServerError, http.StatusNotFound, http.StatusOK, http.StatusUnprocessableEntity, json.Unmarshal, oas.Allowance, oas.Domain, oas.ExtensionTykAPIGateway, oas.FromOASExamples, oas.GatewayTags, oas.Info, oas.ListenPath, oas.Middleware, oas.MockResponse, oas.OAS, oas.Operations, oas.Server, oas.State, oas.TykExtensionConfigParams, oas.Upstream, oas.ValidateRequest, oas.VersionToID, oas.XTykAPIGateway, openapi3.Content, openapi3.Info, openapi3.NewContentWithSchema, openapi3.NewRequestBody, openapi3.NewSchema, openapi3.Operation, openapi3.Paths, openapi3.RequestBodyRef, openapi3.Response, openapi3.Responses, openapi3.Schema, openapi3.SchemaRef, openapi3.Schemas, openapi3.Server, openapi3.Servers, openapi3.T, openapi3.TypeBoolean, os.Stat, strings.TrimSuffix, test.TestCase, testing.T.

TestOAuthAPIRefreshInvalidate

References: http.MethodDelete, http.MethodPost, http.StatusForbidden, http.StatusOK, json.NewDecoder, test.TestCase, testing.T, url.Values.

TestOAuthClientCredsGrant

References: http.MethodPost, http.StatusOK, json.NewDecoder, test.TestCase, testing.T, url.Values.

TestOAuthTokenExpiration

References: assert.NoError, assert.True, http.MethodGet, http.MethodPost, http.StatusOK, http.StatusUnauthorized, json.NewDecoder, test.TestCase, time.Second, url.Values, user.AccessDefinition, user.Policy.

TestOauthMultipleAPIs

References: http.MethodGet, http.MethodPost, http.StatusOK, json.NewDecoder, test.TestCase, url.Values, user.AccessDefinition, user.Policy.

TestOldCachePlugin

References: apidef.CacheOptions, apidef.VersionInfo, assert.NoError, http.StatusOK, storage.RedisCluster, test.TestCase, testing.T, time.Millisecond.

TestOldMockResponse

References: apidef.EndPointMeta, apidef.EndpointMethodMeta, apidef.NoAction, apidef.Reply, apidef.VersionInfo, assert.NoError, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusForbidden, http.StatusOK, http.StatusTeapot, http.StatusUnauthorized, test.Racy, test.TestCase, testing.T.

TestOldVersioning_DefaultVersionEmpty

References: apidef.EndPointMeta, apidef.EndpointMethodMeta, apidef.ExtendedPathsSet, apidef.Reply, apidef.URLLocation, apidef.VersionInfo, assert.NoError, http.MethodGet, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T.

TestOldVersioning_Expires

References: apidef.ExpirationTimeFormat, apidef.URLParamLocation, apidef.VersionInfo, assert.Empty, assert.NoError, assert.NotEmpty, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, time.Now.

TestOldVersioning_StripPath

References: apidef.URLLocation, apidef.VersionInfo, assert.NoError, http.StatusOK, test.TestCase, testing.T.

TestOpenTelemetry

References: assert.Contains, assert.Empty, assert.Equal, assert.Len, assert.Nil, assert.NotEmpty, assert.True, config.Config, http.Request, http.ResponseWriter, http.StatusOK, io.ReadAll, test.TestCase, testing.T.

TestOpenTracing

References: atomic.Value, testing.T, trace.Close, trace.IsEnabled, trace.Logger, trace.NoopTracer, trace.SetInit, trace.SetupTracing, trace.Tracer.

TestOrgKeyHandler_LastUpdated

References: assert.Greater, assert.NoError, assert.NotEmpty, http.MethodGet, http.MethodPost, http.MethodPut, http.StatusOK, json.Unmarshal, test.TestCase, time.Second, user.SessionState.

TestOrgSessionWithRPCDown

References: config.Config, test.Flaky.

TestOrganizationMonitorEnabled

References: config.Config, http.StatusOK, test.Flaky, test.TestCase.

TestOverrideErrors

References: config.TykError, testing.T.

TestParambasedAuth

References: test.TestCase, url.Values, user.AccessDefinition, user.SessionState.

TestParsePoliciesFromRPC

References: assert.NoError, assert.True, json.Marshal, persistentmodel.NewObjectID, testing.T, user.Policy.

TestParseRSAKeyFromJWK

References: assert.NoError, base64.StdEncoding.

TestParseRSAPubKeyFromJWK

References: assert.NoError.

TestPerAPIPolicyUpdate

References: http.MethodGet, http.MethodPost, http.StatusOK, json.Unmarshal, test.TestCase, user.AccessDefinition, user.Policy, user.PolicyPartitions, user.SessionState, uuid.New.

TestPolicyAPI

References: http.StatusNotFound, http.StatusOK, test.TestCase.

TestPopulateHostListByApiSpec

References: apidef.APIDefinition, apidef.HostCheckObject, apidef.UptimeTests, assert.Equal, http.MethodGet, http.MethodPost, testing.T.

TestPost

References: config.EventMessage, config.WebHookHandlerConf.

TestProcessKeySpaceChangesForOauth

References: assert.Equal, assert.NoError, osin.AccessData, testing.T.

TestProcessKeySpaceChanges_ResetQuota

References: assert.Equal, assert.NoError, header.Authorization, http.StatusOK, test.TestCase, user.APILimit, user.AccessDefinition, user.SessionState.

TestProcessKeySpaceChanges_UserKeyReset

References: assert.Equal, config.Config, fmt.Sprintf, gorpc.NewDispatcher, model.GroupLoginRequest, testing.T, time.Millisecond, time.Sleep.

TestProcessRequestLiveQuotaLimit

References: config.Config, http.StatusForbidden, http.StatusOK, test.Flaky, test.TestCase, testing.T, time.Second, time.Sleep.

TestProcessRequestLiveRedisRollingLimiter

References: http.StatusForbidden, http.StatusOK, test.Flaky, test.TestCase, testing.T, time.Second, time.Sleep.

TestProcessRequestOffThreadQuotaLimit

References: config.Config, http.StatusForbidden, http.StatusOK, test.Flaky, test.TestCase, testing.T, time.Millisecond, time.Second, time.Sleep.

TestProcessRequestOffThreadRedisRollingLimiter

References: config.Config, http.StatusForbidden, http.StatusOK, test.Flaky, test.TestCase, testing.T, time.Second, time.Sleep.

TestProxyProtocol

References: bytes.Equal, net.Dial, net.Listen, net.SplitHostPort, strconv.Atoi.

TestProxyUserAgent

References: fmt.Sprintf, test.TestCase.

TestProxyWhenHostIsDown

References: apidef.HostCheckObject, config.Config, http.Get, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, http.StatusServiceUnavailable, httptest.NewServer, time.Millisecond, time.NewTicker, uuid.New.

TestPubSubInternals

References: assert.False, assert.True, errors.New, fmt.Sprintf, testing.T, time.Microsecond.

TestPurgeOAuthClientTokens

References: config.Config, fmt.Sprintf, testing.T, time.Second, time.Sleep, uuid.New.

TestPurgeOAuthClientTokensEndpoint

References: assert.Equal, assert.NoError, config.Config, fmt.Sprintf, http.MethodDelete, http.StatusBadRequest, http.StatusOK, http.StatusUnprocessableEntity, storage.Handler, strconv.FormatInt, test.TestCase, testing.T, time.Now, time.Second, time.Sleep, uuid.New.

TestQuota

References: assert.Equal, atomic.AddInt64, atomic.LoadInt64, http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer, ioutil.ReadAll, json.Unmarshal, test.TestCase, user.SessionState.

TestQuotaNotAppliedWithURLRewrite

References: apidef.URLRewriteMeta, apidef.VersionInfo, http.MethodGet, http.StatusForbidden, http.StatusOK, test.TestCase, user.APILimit, user.AccessDefinition, user.SessionState.

TestQuotaResponseHeaders

References: fmt.Sprintf, header.XRateLimitLimit, header.XRateLimitRemaining, http.StatusForbidden, http.StatusOK, test.TestCase, testing.T, user.APILimit, user.AccessDefinition, user.Policy, user.PolicyPartitions, user.SessionState.

TestRLClosed

References: httptest.NewRecorder, uuid.New.

TestRLOpen

References: httptest.NewRecorder.

TestRLOpenWithReload

References: httptest.NewRecorder.

TestRPCStorageHandler_BuildNodeInfo

References: assert.Equal, assert.Nil, config.Config, json.Marshal, model.GWStats, model.HostDetails, model.NodeData, testing.T, user.Policy.

TestRPCStorageHandler_Disconnect

References: assert.EqualError, errors.New, testing.T.

TestRPCUpdateKey

References: assert.Equal, assert.NoError, assert.True, config.Config, header.Authorization, http.StatusOK, test.TestCase, testing.T, user.APILimit, user.AccessDefinition, user.SessionState.

TestRSAAuthSessionKeyMissing

References: certs.GenServerCertificate, fmt.Sprintf, httptest.NewRecorder, pem.Block, pem.EncodeToMemory, rsa.PrivateKey, sync.WaitGroup, time.Millisecond, x509.MarshalPKIXPublicKey, x509.ParseCertificate.

TestRSAAuthSessionPass

References: certs.GenServerCertificate, fmt.Sprintf, httptest.NewRecorder, pem.Block, pem.EncodeToMemory, rsa.PrivateKey, sync.WaitGroup, time.Millisecond, x509.MarshalPKIXPublicKey, x509.ParseCertificate.

TestRSARequestSigning

References: apidef.AuthConfig, crypto.GenServerCertificate, httptest.NewRecorder, pem.Block, pem.EncodeToMemory, testing.T, time.Now, x509.MarshalPKIXPublicKey, x509.ParseCertificate.

TestRateLimitForAPIAndRateLimitAndQuotaCheck

References: apidef.GlobalRateLimit, http.StatusOK, http.StatusTooManyRequests, test.TestCase, time.Millisecond, time.Now, user.SessionState.

TestRateLimitForAPI_EnabledForSpec

References: apidef.APIDefinition, apidef.GlobalRateLimit, assert.False.

TestRateLimit_Unlimited

References: header.Authorization, http.StatusOK, http.StatusTooManyRequests, test.TestCase, testing.T, user.AccessDefinition, user.SessionState.

TestRecordDetail

References: assert.Equal, context.Context, context.WithValue, ctxpkg.OrgSessionContext, ctxpkg.SessionData, testing.T, user.SessionState.

TestRecordUptimeAnalytics

References: apidef.APIDefinition, http.MethodGet, http.StatusOK, storage.RedisCluster.

TestRecoverFromLoadApiPanic

References: apidef.APIDefinition, oas.OAS, strings.Contains, testing.T.

TestRedisCacheMiddleware

References: analytics.AnalyticsRecord, apidef.VersionInfo, assert.Contains, assert.Equal, assert.NoError, base64.StdEncoding, config.Config, http.StatusOK, test.TestCase, testing.T.

TestRedisCacheMiddlewareUnit

References: assert.Equal, assert.Error, assert.False, assert.NoError, assert.True, fmt.Sprint, strings.HasSuffix, testing.T, time.Now.

TestRedisCacheMiddlewareV2

References: analytics.AnalyticsRecord, apidef.VersionInfo, assert.Contains, assert.Equal, assert.NoError, assert.NotEmpty, assert.True, base64.StdEncoding, config.Config, fmt.Sprintf, http.StatusOK, test.TestCase, testing.T.

TestRegexExtractor

References: apidef.BodySource, apidef.FormSource, apidef.HeaderSource, apidef.RegexExtractor, storage.TokenOrg, testing.T.

TestReloadLoop_basic

References: atomic.Value.

TestReloadLoop_group

References: http.Get, http.StatusOK, test.Flaky.

TestReloadLoop_handler

References: atomic.Value, http.MethodGet, httptest.NewRecorder, httptest.NewRequest.

TestReloadLoop_handlerWithBlock

References: http.MethodGet, httptest.NewRecorder, httptest.NewRequest, time.After, time.Millisecond, url.Values.

TestReplaceSecrets

References: apidef.AuthConfig, apidef.AuthTokenType, apidef.BasicType, apidef.OAuthType, assert.Equal, config.Config.

TestRequestBodyLimit

References: config.Config, http.StatusOK, http.StatusRequestEntityTooLarge, strings.Repeat, test.TestCase.

TestRequestIP

References: http.Header, http.Request, request.RealIP.

TestRequestIPHops

TestRequestSigning_getRequestPath

References: assert.Equal, http.MethodGet, http.NewRequest, testing.T, url.URL.

TestRequestSigning_isRequestSigningConfigValid

References: apidef.RequestSigningMeta, assert.Equal.

TestRequestSizeLimit

References: apidef.RequestSizeMeta, apidef.VersionInfo, assert.False, assert.True, bytes.NewBufferString, context.Background, http.MethodPatch, http.MethodPost, http.MethodPut, http.StatusBadRequest, http.StatusLengthRequired, http.StatusOK, httptest.NewRecorder, httptest.NewRequest, logrus.NewNullLogger, require.Equal, require.Errorf, strings.Repeat, test.TestCase, testing.T.

TestRequestThrottling

References: test.Flaky, testing.T.

TestResetQuotaObfuscate

References: assert.Equal, config.Config, testing.T.

TestResponseCacheMiddleware

References: assert.NoError.

TestResponseGoPluginMiddlewareBase

References: require.Equal.

TestResponseGoPluginMiddlewareInit

References: apidef.MiddlewareDefinition, assert.Error.

TestResponseGoPluginMiddlewareName

References: require.Equal.

TestResponseHeaderInjection

References: fmt.Sprintf, test.TestCase.

TestResponseOverride

References: config.CoProcessConfig, test.GetPythonVersion, test.TestCase, testing.T.

TestResponseTransformMiddleware_Enabled

References: apidef.APIDefinition, apidef.ExtendedPathsSet, apidef.TemplateData, apidef.TemplateMeta, apidef.VersionData, apidef.VersionInfo, assert.Equal, base64.StdEncoding, http.MethodGet, testing.T.

TestReverseProxyAllDown

References: apidef.NewHostListFromList, apidef.TykEvent, bytes.Buffer, config.Config, config.EventMessage, config.TykEventHandler, httptest.NewRecorder, sync.WaitGroup, texttemplate.Must, texttemplate.New, url.Parse, uuid.New.

TestReverseProxyDnsCache

References: apidef.APIDefinition, config.Config, config.DnsCacheConfig, config.NoCacheStrategy, dnscache.MockStorage, http.Header, http.MethodGet, http.MethodPatch, http.MethodPost, httptest.NewRecorder, strings.Join, test.Flaky, test.InitDNSMock, test.IsDnsRecordsAddrsEqualsTo, testing.T, url.Parse.

TestReverseProxyRetainHost

References: apidef.APIDefinition, ctx.RetainHost, http.MethodGet, testing.T, url.Parse.

TestReverseProxyWebSocketCancelation

References: apidef.APIDefinition, bufio.NewReader, config.Config, context.WithCancel, errors.Is, fmt.Sprintf, http.Error, http.HandlerFunc, http.Hijacker, http.NewRequest, http.Request, http.ResponseWriter, httptest.NewServer, io.EOF, io.ReadWriteCloser, io.WriteString, time.Millisecond, time.Sleep, url.Parse.

TestRewriter

References: testing.T.

TestRewriterTriggers

References: apidef.All, apidef.Any, apidef.RoutingTrigger, apidef.RoutingTriggerOptions, apidef.StringRegexMap, apidef.URLRewriteMeta, assert.NoError, assert.NotEqual, bytes.NewBuffer, http.NewRequest, http.Request, io.ReadAll, testing.T, user.SessionState.

TestRotateClientSecretHandler

References: bytes.Buffer, fmt.Sprintf, http.MethodPost, http.MethodPut, http.StatusOK, json.NewDecoder, json.NewEncoder, test.MarshalJSON, test.TestCase, testing.T, user.AccessDefinition, user.Policy.

TestRoundRobin

TestSSE

References: analytics.AnalyticsRecord, assert.Equal, assert.NoError, atomic.Int32, config.Config, require.NoError, testing.T.

TestSSLForceCommonName

References: crypto.GenCertificate, http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewUnstartedServer, pkix.Name, strings.Replace, test.Flaky, test.NewClientLocal, test.TestCase, testing.T, tls.Certificate, tls.Config, tls.VersionTLS12, x509.Certificate.

TestSchemaApi

References: http.MethodGet, http.StatusNotFound, http.StatusOK, json.Unmarshal, test.TestCase, testing.T.

TestServiceDiscovery_CONSUL

TestServiceDiscovery_ETCD_NESTED_LIST

TestServiceDiscovery_ETCD_NESTED_NOLIST

TestServiceDiscovery_ETCD_NOLIST

TestServiceDiscovery_EUREKA

TestServiceDiscovery_MESOSPHERE

TestServiceDiscovery_NESTED_CONSUL

TestSessionLifetimeRespectsKeyExpiration

References: http.StatusNotFound, http.StatusOK, test.TestCase, testing.T, time.Second, user.AccessDefinition, user.SessionState.

TestSessionLimiter_RateLimitInfo

References: assert.Equal, config.Default, http.MethodGet, http.MethodPost, httptest.NewRequest, storage.HashStr, testing.T, user.Endpoint, user.EndpointMethod, user.EndpointRateLimitInfo, user.Endpoints, user.RateLimit.

TestSessionLimiter_RedisQuotaExceeded_PerAPI

References: assert.Equal, fmt.Sprintf, headers2.Authorization, http.StatusOK, ioutil.ReadAll, json.Unmarshal, test.TestCase, testing.T, user.APILimit, user.AccessDefinition, user.SessionState, uuid.New.

TestSetCustomHeaderMultipleValues

References: http.Header, reflect.DeepEqual, testing.T.

TestSignatureValidation

References: apidef.AuthConfig, apidef.AuthTokenType, apidef.SignatureConfig, hex.EncodeToString, http.MethodPost, http.StatusForbidden, http.StatusOK, http.StatusUnauthorized, signaturevalidator.MasheryMd5sum, storage.GenerateToken, test.Flaky, test.TestCase, testing.T, time.Now, user.AccessDefinition, user.SessionState.

TestSingleJoiningSlash

References: assert.Equal, fmt.Sprintf, testing.T.

TestSkipTargetPassEscapingOff

References: test.TestCase, testing.T.

TestSkipTargetPassEscapingOffWithSkipURLCleaningTrue

References: config.Config, test.TestCase, testing.T.

TestSkipUrlCleaning

References: http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer, test.TestCase.

TestSortAPISpecs

References: apidef.APIDefinition, apidef.ProxyConfig, testing.T.

TestSortSpecsByListenPath

References: apidef.APIDefinition, apidef.ProxyConfig, reflect.DeepEqual, testing.T.

TestStartPoller

References: storage.RedisCluster.

TestStaticMTLSAPI

References: assert.ErrorContains, assert.NoError, assert.Zero, bytes.Join, certs.CertificatePublic, certs.GetCertIDAndChainPEM, config.Config, crypto.ErrCertExpired, crypto.GenCertificate, crypto.GenServerCertificate, crypto.GenerateClientCertAndKeyChain, crypto.GenerateRSAPublicKey, crypto.GenerateRootCertAndKey, crypto.GenerateServerCertAndKeyChain, crypto.HexSHA256, fmt.Sprintf, gomock.NewController, http.Client, http.MethodGet, http.NewRequest, http.StatusForbidden, http.StatusOK, http.Transport, mock.NewMockCertificateManager, pkix.Extension, test.TestCase, testing.T, time.Now, tls.Certificate, tls.CertificateRequestInfo, tls.Config, tls.X509KeyPair, url.Parse, x509.Certificate.

TestStripAuth_stripFromHeaders

References: apidef.APIDefinition, apidef.AuthConfig, apidef.AuthTokenType, fmt.Sprintf, http.NewRequest, testing.T.

TestStripAuth_stripFromParams

References: apidef.APIDefinition, fmt.Sprintf, http.NewRequest, testing.T, url.Values.

TestStripBearer

References: testing.T.

TestStripPathWithURLRewrite

References: json.Unmarshal, test.TestCase, testing.T.

TestSyncAPISpecsDashboardJSONFailure

References: http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer, sync.WaitGroup.

TestSyncAPISpecsDashboardSuccess

References: http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer, sync.WaitGroup.

TestSyncAPISpecsRPCFailure_CheckGlobals

References: gorpc.NewDispatcher, model.DefRequest, test.Flaky.

TestSyncAPISpecsRPCSuccess

References: config.Config, gorpc.NewDispatcher, gorpc.NewTCPServer, gorpc.NilErrorLogger, model.DefRequest, rpc.ResetEmergencyMode, rpc.SetEmergencyMode, rpc.UseSyncLoginRPC, test.Flaky, test.TestCase, testing.T, time.Millisecond, time.Second, time.Sleep.

TestSyncAPISpecsRPC_redis_failure

References: gorpc.NewDispatcher, http.StatusOK, model.DefRequest, test.Flaky, test.TestCase, testing.T, time.After, time.Second, time.Sleep.

TestSyncHeadersAndMultiValueHeaders

References: coprocess.Header, testing.T.

TestTCPDial_with_service_discovery

References: atomic.Value, http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewServer, json.NewEncoder, net.Dial, net.Listen, net.SplitHostPort, reflect.DeepEqual, strconv.Atoi.

TestTCP_missing_port

TestTLSTyk_H2cUpstream

References: certs.GenCertificate, certs.GenServerCertificate, certs.GetCertIDAndChainPEM, config.Config, h2c.NewHandler, http.HandlerFunc, http.Request, http.ResponseWriter, http.Transport, http2.ConfigureTransport, http2.Server, httptest.NewUnstartedServer, strings.Replace, test.TestCase, x509.Certificate.

TestTagHeaders

TestTestCheckerTCPHosts_correct_answers

References: apidef.CheckCommand, context.Background, context.WithCancel, net.Listen, net.Listener.

TestTestCheckerTCPHosts_correct_answers_proxy_protocol

References: apidef.CheckCommand, context.Background, context.WithCancel, net.Listen, net.Listener, proxyproto.Listener.

TestTestCheckerTCPHosts_correct_wrong_answers

References: apidef.CheckCommand, context.Background, context.Context, context.WithCancel, net.Listen, net.Listener.

TestTimeValidateClaims

References: assert.Nil, assert.True, fmt.Sprintf, json.Unmarshal, testing.T, time.Duration, time.Now, time.Second.

TestTimeoutPrioritization

References: apidef.HardTimeoutMeta, apidef.VersionInfo, config.Config, http.HandlerFunc, http.MethodGet, http.Request, http.ResponseWriter, http.StatusGatewayTimeout, http.StatusNotFound, http.StatusOK, httptest.NewServer, strings.HasPrefix, test.TestCase, testing.T, time.Millisecond, time.Second, time.Sleep.

TestTokenEndpointHeaders

References: http.MethodPost, http.StatusForbidden, http.StatusOK, test.TestCase, url.Values.

TestTraceHttpRequest_toRequest

References: assert.Equal, assert.NoError, http.Header, http.MethodPost, ioutil.ReadAll.

TestTracing

References: apidef.APIDefinition, apidef.AuthConfig, apidef.AuthTokenType, http.MethodPost, http.StatusBadRequest, http.StatusOK, oas.OAS, test.TestCase, testing.T.

TestTransformHeaders_EnabledForSpec

References: apidef.APIDefinition, apidef.HeaderInjectionMeta, apidef.VersionInfo, assert.False, assert.True.

TestTransformJSONMarshalJSONArrayInput

References: apidef.APIDefinition, ioutil.ReadAll.

TestTransformJSONMarshalJSONInput

References: apidef.APIDefinition, ioutil.ReadAll.

TestTransformJSONMarshalXMLInput

References: apidef.APIDefinition, ioutil.ReadAll.

TestTransformNonAscii

References: apidef.APIDefinition, ioutil.ReadAll, test.Flaky.

TestTransformRequestBody

References: apidef.RequestJSON, apidef.TemplateData, apidef.TemplateMeta, apidef.UseBlob, apidef.VersionInfo, base64.StdEncoding, http.MethodGet, http.StatusOK, test.TestCase, testing.T.

TestTransformResponseBody

References: apidef.TemplateData, apidef.TemplateMeta, apidef.VersionInfo, base64.StdEncoding, http.MethodGet, test.TestCase, testing.T.

TestTransformResponseWithURLRewrite

References: apidef.TemplateData, apidef.TemplateMeta, apidef.URLRewriteMeta, apidef.VersionInfo, base64.StdEncoding, test.TestCase, testing.T.

TestTransformResponse_ContextVars

References: apidef.TemplateData, apidef.TemplateMeta, apidef.VersionInfo, base64.StdEncoding, test.TestCase.

TestTransformResponse_WithCache

References: apidef.TemplateData, apidef.TemplateMeta, apidef.VersionInfo, base64.StdEncoding, test.TestCase, time.Millisecond.

TestTransformXMLCrash

References: apidef.APIDefinition, apidef.RequestXML, apidef.Template, strings.NewReader, texttemplate.Must.

TestTransformXMLMarshal

References: apidef.APIDefinition, apidef.RequestInputType, apidef.RequestJSON, apidef.RequestXML, ioutil.ReadAll, testing.T.

TestTykMakeHTTPRequest

References: config.Config, test.TestCase, testing.T.

TestTykRateLimitsStatusOfAPI

References: fmt.Sprintf, http.StatusOK, test.TestCase, user.AccessDefinition, user.SessionState.

TestURLReplacer

References: analytics.AnalyticsRecord, assert.Equal, config.Config.

TestURLRewriteCaseSensitivity

References: apidef.URLRewriteMeta, apidef.VersionInfo, test.TestCase, testing.T.

TestURLRewriteMiddleware_CheckHostRewrite

References: assert.Equal, ctx.RetainHost, http.Request, testing.T.

TestURLRewrites

References: apidef.VersionInfo, http.StatusOK, json.Unmarshal, test.TestCase, testing.T.

TestUpdateKeyWithCert

References: apidef.AuthConfig, certs.GenCertificate, fmt.Sprintf, http.MethodPut, test.MarshalJSON, test.TestCase, testing.T, user.AccessDefinition, user.Policy, user.SessionState, x509.Certificate.

TestUpdateOauthClientHandler

References: bytes.Buffer, fmt.Sprintf, http.MethodPost, http.MethodPut, http.StatusOK, json.NewEncoder, test.MarshalJSON, test.TestCase, testing.T, user.AccessDefinition, user.Policy.

TestUpstreamCertificates_WithProtocolTCP

References: assert.Equal, assert.Error, assert.NoError, crypto.GenCertificate, crypto.GenServerCertificate, net.Dial, testing.T, tls.Certificate, tls.Config, tls.Listen, tls.RequireAndVerifyClientCert, tls.X509KeyPair, x509.Certificate, x509.NewCertPool.

TestUpstreamMutualTLS

References: crypto.GenCertificate, fmt.Sprintf, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusInternalServerError, http.StatusOK, httptest.NewUnstartedServer, strings.Contains, test.LocalDialer, test.NewClientLocal, test.TestCase, testing.T, tls.Config, tls.RequireAndVerifyClientCert, tls.VersionTLS12, url.Parse, x509.Certificate, x509.NewCertPool, x509.ParseCertificate.

TestUptimeTests_When_UptimeTests_Disabled_In_GW_Config

References: apidef.HostCheckObject, assert.Equal, assert.Nil, config.Config, http.Get, http.HandlerFunc, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer.

TestValToStr

TestValidateJSONSchema

References: http.MethodPost, http.StatusBadRequest, http.StatusOK, http.StatusUnprocessableEntity, strings.Contains, test.TestCase, testing.T.

TestValidateRequest

References: apidef.APIDefinition, assert.NoError, context.Background, http.MethodPost, http.StatusOK, http.StatusTeapot, http.StatusUnprocessableEntity, oas.Middleware, oas.OAS, oas.Operations, oas.ValidateRequest, oas.XTykAPIGateway, openapi3.NewLoader, test.NewClientLocal, test.TestCase, testing.T.

TestValidateRequest_AfterMigration

References: apidef.ValidatePathMeta, apidef.VersionInfo, assert.NoError, http.MethodPost, http.StatusOK, http.StatusTeapot, oas.MigrateAndFillOAS, test.TestCase.

TestValueExtractor

References: apidef.FormSource, apidef.HeaderSource, apidef.ValueExtractor, storage.TokenOrg, testing.T.

TestVersionInfo_GlobalHeadersEnabled

References: apidef.VersionInfo, assert.False, assert.True.

TestVersionInfo_GlobalResponseHeadersEnabled

References: apidef.VersionInfo, assert.False, assert.True.

TestVersionInfo_HasEndpointReqHeader

References: apidef.HeaderInjectionMeta, apidef.VersionInfo, assert.False, assert.True.

TestVersionInfo_HasEndpointResHeader

References: apidef.HeaderInjectionMeta, apidef.VersionInfo, assert.False, assert.True.

TestVersioning

References: test.TestCase.

TestVirtualEndpoint

References: test.TestCase.

TestVirtualEndpoint500

TestVirtualEndpoint500NotCached

TestVirtualEndpointBatch

References: apidef.ExtendedPathsSet, apidef.UseBlob, apidef.VersionInfo, apidef.VirtualMeta, base64.StdEncoding, certs.GenCertificate, http.HandlerFunc, http.Request, http.ResponseWriter, httptest.NewUnstartedServer, strings.Replace, strings.TrimPrefix, test.TestCase, testing.T, tls.Config, tls.RequireAndVerifyClientCert, tls.VersionTLS12, x509.Certificate, x509.NewCertPool, x509.ParseCertificate.

TestVirtualEndpointDisabled

References: test.TestCase.

TestVirtualEndpointNotCached

References: test.TestCase.

TestVirtualEndpointSessionMetadata

References: http.StatusAccepted, test.TestCase, user.AccessDefinition, user.SessionState.

TestWebhookContentTypeHeader

References: assert.NoError, config.WebHookHandlerConf, filepath.Join, header.ContentType, testing.T.

TestWebsocketsAndHTTPEndpointMatch

References: http.StatusOK, strings.Replace, test.TestCase, websocket.BinaryMessage, websocket.DefaultDialer.

TestWebsocketsSeveralOpenClose

References: strings.Replace, websocket.BinaryMessage, websocket.DefaultDialer.

TestWhitelist

References: apidef.EndPointMeta, apidef.VersionInfo, http.StatusForbidden, http.StatusOK, json.Unmarshal, test.TestCase, testing.T.

TestWhitelistMethodWithAdditionalMiddleware

References: apidef.VersionInfo, http.StatusForbidden, json.Unmarshal, test.TestCase, testing.T.

TestWithURLRewrite

References: apidef.URLRewriteMeta, http.MethodGet, http.StatusOK, test.TestCase, testing.T, user.SessionState.

TestWrappedServeHTTP

References: assert.Equal, assert.Nil, assert.NotNil, errors.New, http.MethodGet, http.MethodPost, http.StatusInternalServerError, httptest.NewRequest, time.Second, time.Sleep.

TestXPathExtractor

References: apidef.BodySource, apidef.FormSource, apidef.HeaderSource, apidef.XPathExtractor, storage.TokenOrg, testing.T.

Test_BuildDashboardConnStr

References: assert.Equal, config.Config, time.Second, time.Sleep.

Test_DashboardLifecycle

References: assert.False, assert.True.

Test_LoadAPIsFromRPC

References: apidef.APIDefinition, assert.Equal, assert.NoError, model.MergedAPI, persistentmodel.NewObjectID, policy.RPCDataLoaderMock, rpc.ResetEmergencyMode, rpc.SetEmergencyMode, rpc.SetLoadCounts, testing.T.

Test_addBodyHash

References: hash.Hash, hex.EncodeToString, http.MethodPatch, http.MethodPost, http.MethodPut, http.NewRequest, http.Request, md5.New, strings.NewReader, testing.T.

Test_getAPIURL

References: apidef.APIDefinition, apidef.ProxyConfig, assert.Equalf, config.Config, config.HttpServerOptionsConfig, testing.T.

Test_getIDExtractor

References: apidef.APIDefinition, apidef.HeaderSource, apidef.MiddlewareDefinition, apidef.MiddlewareIdExtractor, apidef.MiddlewareSection, apidef.ValueExtractor, assert.Equal, testing.T.

Test_getOAuthClientIDFromClaim

References: apidef.APIDefinition, assert.Equal, testing.T.

Test_handleRequestLimits

References: assert.Equal, fmt.Sprintf, http.MethodDelete, http.MethodGet, http.MethodPost, http.StatusOK, http.StatusRequestEntityTooLarge, httptest.NewRecorder, httptest.NewRequest, io.Reader, strings.NewReader, testing.T.

Test_isBodyHashRequired

References: http.MethodGet, http.MethodPatch, http.MethodPost, http.MethodPut, http.NewRequest, http.Request, strings.NewReader, testing.T.

Test_isExpired

References: assert.False, assert.True, fmt.Sprintf, json.Unmarshal, time.Duration, time.Minute, time.Now.

Test_isSafeMethod

References: http.MethodConnect, http.MethodDelete, http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodPatch, http.MethodPost, http.MethodPut, http.MethodTrace, testing.T.

Test_mockFromConfig

References: assert.Equal, http.StatusOK, http.StatusTeapot, oas.Header, oas.MockResponse, testing.T.

Test_mockFromOAS

References: assert.Contains, assert.Equal, assert.EqualError, assert.Len, assert.NoError, http.Header, http.Request, http.StatusAlreadyReported, http.StatusMethodNotAllowed, http.StatusNotFound, http.StatusOK, http.StatusTeapot, oas.FromOASExamples, oas.Header, openapi3.Content, openapi3.Example, openapi3.ExampleRef, openapi3.Examples, openapi3.Header, openapi3.HeaderRef, openapi3.Headers, openapi3.NewOperation, openapi3.Parameter, openapi3.Response, openapi3.ResponseRef, openapi3.Responses, openapi3.Schema, openapi3.SchemaRef, testing.T.

Test_shouldAddConfigData

References: apidef.APIDefinition, assert.Equal, testing.T.

Test_shouldReloadSpec

References: apidef.APIDefinition, apidef.ExtendedPathsSet, apidef.GoPluginDriver, apidef.GrpcDriver, apidef.MiddlewareDefinition, apidef.MiddlewareSection, apidef.VersionData, apidef.VersionInfo, apidef.VirtualMeta, assert.True, testing.T.

TestHandleError_text_xml

References: bytes.TrimSpace, filepath.Join, header.ContentType, header.TextXML, http.StatusInternalServerError, ioutil.WriteFile, os.Remove, strings.TrimSpace, test.TestCase.

TestNewWrappedServeHTTP

References: apidef.APIDefinition, apidef.ExtendedPathsSet, apidef.HeaderInjectionMeta, apidef.URLRewriteMeta, apidef.VersionInfo, url.Parse.

Benchmark functions

BenchmarkApiReload

References: strconv.Itoa.

BenchmarkBasicAuth

References: test.TestCase.

BenchmarkBasicAuth_CacheDisabled

References: test.TestCase.

BenchmarkBasicAuth_CacheEnabled

References: test.TestCase.

BenchmarkBearerTokenAuthKeySession

References: httptest.NewRecorder.

BenchmarkContextVarsMiddleware

References: test.TestCase.

BenchmarkContextVarsMiddlewareProcessRequest

References: http.StatusOK, httptest.NewRequest, io.Reader, strings.NewReader, testing.B.

BenchmarkCopyRequestResponse

References: http.Request, http.Response, ioutil.NopCloser, strings.NewReader, strings.Repeat.

BenchmarkDefaultVersion

References: http.StatusForbidden, http.StatusOK, test.TestCase.

BenchmarkGetVersionFromRequest

References: apidef.DefaultAPIVersionKey, apidef.HeaderLocation, apidef.URLLocation, apidef.URLParamLocation, apidef.VersionInfo, http.StatusForbidden, http.StatusOK, test.TestCase, testing.B.

BenchmarkGraphqlUDG

References: apidef.GraphQLConfigVersion2, apidef.GraphQLEngineDataSource, apidef.GraphQLEngineDataSourceConfigREST, apidef.GraphQLExecutionModeExecutionEngine, config.Config, graphql.Request, http.StatusOK, json.Unmarshal, require.NoError, test.TestCase.

BenchmarkHMACAuthSessionPass

References: fmt.Sprintf, httptest.NewRecorder, sha1.New, sync.WaitGroup.

BenchmarkHMACAuthSessionPassWithHeaderField

References: fmt.Sprintf, httptest.NewRecorder, sha1.New, sync.WaitGroup.

BenchmarkIPBlacklistMiddleware

References: header.XRealIP, httptest.NewRecorder.

BenchmarkIPMiddlewarePass

References: header.XRealIP, httptest.NewRecorder.

BenchmarkInitGenericEventHandlers

BenchmarkJWTSessionHMAC

References: http.StatusOK, test.TestCase.

BenchmarkJWTSessionRSA

References: http.StatusOK, test.TestCase.

BenchmarkJWTSessionRSABearer

References: http.StatusOK, test.TestCase.

BenchmarkJWTSessionRSAWithEncodedJWK

References: base64.StdEncoding, http.StatusOK, test.TestCase.

BenchmarkJWTSessionRSAWithJWK

References: http.StatusOK, test.TestCase.

BenchmarkJWTSessionRSAWithRawSource

References: http.StatusOK, test.TestCase.

BenchmarkJWTSessionRSAWithRawSourceOnWithClientID

References: http.StatusOK, test.TestCase.

BenchmarkKeyHandler_CreateKeyHandler

References: assert.Equal, bytes.NewBuffer, http.MethodPost, http.NewRequest, httptest.NewRecorder, json.Marshal, require.NoError, user.AccessDefinition, user.Policy, user.SessionState.

BenchmarkLargeResponsePayload

References: assert.NoError, bytes.Repeat, config.Config, http.HandlerFunc, http.MethodGet, http.Request, http.ResponseWriter, http.StatusOK, httptest.NewServer, strconv.Itoa, test.TestCase.

BenchmarkMultiAuthBackwardsCompatibleSession

References: fmt.Sprintf, httptest.NewRecorder.

BenchmarkMultiSession_BA_Standard_OK

References: httptest.NewRecorder.

BenchmarkProcessRequestLiveQuotaLimit

References: config.Config, http.StatusOK, test.TestCase.

BenchmarkProcessRequestLiveRedisRollingLimiter

References: config.Config, http.StatusOK, test.TestCase.

BenchmarkProcessRequestOffThreadQuotaLimit

References: config.Config, http.StatusOK, test.TestCase.

BenchmarkProcessRequestOffThreadRedisRollingLimiter

References: config.Config, http.StatusOK, test.TestCase.

BenchmarkPurgeLapsedOAuthTokens

References: config.Config, context.Background, fmt.Sprintf, redis.NewClient, redis.UniversalClient, redis.UniversalOptions, redis.Z, redis.ZRangeArgs, require.NoError, testing.TB, time.Now, time.Second, time.Since.

BenchmarkRSAAuthSessionPass

References: certs.GenServerCertificate, fmt.Sprintf, httptest.NewRecorder, pem.Block, pem.EncodeToMemory, rsa.PrivateKey, sync.WaitGroup, x509.MarshalPKIXPublicKey, x509.ParseCertificate.

BenchmarkRegexExtractor

References: apidef.BodySource, apidef.FormSource, apidef.HeaderSource, apidef.RegexExtractor, testing.B.

BenchmarkRequestIPHops

BenchmarkResponseHeaderInjection

References: fmt.Sprintf, test.TestCase.

BenchmarkRewriter

BenchmarkStripAuth_stripFromHeaders

References: apidef.APIDefinition, http.NewRequest.

BenchmarkStripAuth_stripFromParams

References: apidef.APIDefinition, http.NewRequest, url.Values.

BenchmarkStripBearer

BenchmarkTagHeaders

BenchmarkTransformJSONMarshal

References: apidef.APIDefinition.

BenchmarkTransformNonAscii

References: apidef.APIDefinition.

BenchmarkURLReplacer

References: analytics.AnalyticsRecord, config.Config.

BenchmarkValidateJSONSchema

References: http.StatusBadRequest, http.StatusOK, http.StatusUnprocessableEntity, test.TestCase.

BenchmarkValueExtractor

References: apidef.FormSource, apidef.HeaderSource, apidef.ValueExtractor, testing.B.

BenchmarkVersioning

References: test.TestCase.

BenchmarkVirtualEndpoint

References: test.TestCase.

BenchmarkWrappedServeHTTP

References: http.MethodGet, http.NewRequest, httptest.NewRecorder.

BenchmarkXPathExtractor

References: apidef.BodySource, apidef.FormSource, apidef.HeaderSource, apidef.XPathExtractor, testing.B.