forked from TykTechnologies/tyk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler_success.go
132 lines (107 loc) · 3.44 KB
/
handler_success.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main
import (
"github.com/gorilla/context"
"net/http"
// "net/http/httputil"
"runtime/pprof"
"strconv"
"strings"
"time"
)
// ContextKey is a key type to avoid collisions
type ContextKey int
// Enums for keys to be stored in a session context - this is how gorilla expects
// these to be implemented and is lifted pretty much from docs
const (
SessionData = 0
AuthHeaderValue = 1
)
// TykMiddleware wraps up the ApiSpec and Proxy objects to be included in a
// middleware handler, this can probably be handled better.
type TykMiddleware struct {
Spec APISpec
Proxy *ReverseProxy
}
// 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 TykMiddleware) CheckSessionAndIdentityForValidKey(key string) (SessionState, bool) {
// Try and get the session from the session store
var thisSession SessionState
var found bool
thisSession, found = t.Spec.SessionManager.GetSessionDetail(key)
if found {
// If exists, assume it has been authorized and pass on
return thisSession, true
}
// 2. If not there, get it from the AuthorizationHandler
thisSession, found = t.Spec.AuthManager.IsKeyAuthorised(key)
if found {
// If not in Session, and got it from AuthHandler, create a session with a new TTL
log.Info("Recreating session for key: ", key)
t.Spec.SessionManager.UpdateSession(key, thisSession, t.Spec.APIDefinition.SessionLifetime)
}
return thisSession, found
}
// SuccessHandler represents the final ServeHTTP() request for a proxied API request
type SuccessHandler struct {
TykMiddleware
}
// 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) {
// Make sure we get the correct target URL
if s.Spec.APIDefinition.Proxy.StripListenPath {
r.URL.Path = strings.Replace(r.URL.Path, s.Spec.Proxy.ListenPath, "", 1)
}
t1 := time.Now()
s.Proxy.ServeHTTP(w, r)
t2 := time.Now()
millisec := float64(t2.UnixNano()-t1.UnixNano()) * 0.000001
log.Debug("Upstream request took (ms): ", millisec)
if config.StoreAnalytics(r) {
t := time.Now()
// Track the key ID if it exists
authHeaderValue := context.Get(r, AuthHeaderValue)
keyName := ""
if authHeaderValue != nil {
keyName = authHeaderValue.(string)
}
// 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 := ""
thisSessionState := context.Get(r, SessionData)
if thisSessionState != nil {
OauthClientID = thisSessionState.(SessionState).OauthClientID
}
thisRecord := AnalyticsRecord{
r.Method,
r.URL.Path,
r.ContentLength,
r.Header.Get("User-Agent"),
t.Day(),
t.Month(),
t.Year(),
t.Hour(),
200,
keyName,
t,
version,
s.Spec.APIDefinition.Name,
s.Spec.APIDefinition.APIID,
s.Spec.APIDefinition.OrgID,
OauthClientID,
int64(millisec)}
go analytics.RecordHit(thisRecord)
}
// Report in health check
ReportHealthCheckValue(s.Spec.Health, RequestLog, strconv.FormatInt(int64(millisec), 10))
if doMemoryProfile {
pprof.WriteHeapProfile(profileFile)
}
context.Clear(r)
}