forked from TykTechnologies/tyk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
middleware.go
147 lines (127 loc) · 3.95 KB
/
middleware.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package main
import (
"errors"
"net/http"
"strconv"
"time"
"github.com/gocraft/health"
"github.com/justinas/alice"
"github.com/paulbellamy/ratecounter"
)
const mwStatusRespond = 666
var GlobalRate = ratecounter.NewRateCounter(1 * time.Second)
type TykMiddleware interface {
Init()
Base() *BaseMiddleware
GetConfig() (interface{}, error)
ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (error, int) // Handles request
IsEnabledForSpec() bool
GetName() string
}
func CreateDynamicMiddleware(name string, isPre, useSession bool, baseMid *BaseMiddleware) func(http.Handler) http.Handler {
dMiddleware := &DynamicMiddleware{
BaseMiddleware: baseMid,
MiddlewareClassName: name,
Pre: isPre,
UseSession: useSession,
}
return CreateMiddleware(dMiddleware)
}
func CreateDynamicAuthMiddleware(name string, baseMid *BaseMiddleware) func(http.Handler) http.Handler {
return CreateDynamicMiddleware(name, true, false, baseMid)
}
// Generic middleware caller to make extension easier
func CreateMiddleware(mw TykMiddleware) func(http.Handler) http.Handler {
// construct a new instance
mw.Init()
// Pull the configuration
mwConf, err := mw.GetConfig()
if err != nil {
log.Fatal("[Middleware] Configuration load failed")
}
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
job := instrument.NewJob("MiddlewareCall")
meta := health.Kvs{
"from_ip": r.RemoteAddr,
"method": r.Method,
"endpoint": r.URL.Path,
"raw_url": r.URL.String(),
"size": strconv.Itoa(int(r.ContentLength)),
"mw_name": mw.GetName(),
}
eventName := mw.GetName() + "." + "executed"
job.EventKv("executed", meta)
job.EventKv(eventName, meta)
startTime := time.Now()
if mw.Base().Spec.CORS.OptionsPassthrough && r.Method == "OPTIONS" {
h.ServeHTTP(w, r)
return
}
err, errCode := mw.ProcessRequest(w, r, mwConf)
if err != nil {
handler := ErrorHandler{mw.Base()}
handler.HandleError(w, r, err.Error(), errCode)
meta["error"] = err.Error()
job.TimingKv("exec_time", time.Since(startTime).Nanoseconds(), meta)
job.TimingKv(eventName+".exec_time", time.Since(startTime).Nanoseconds(), meta)
return
}
// Special code, bypasses all other execution
if errCode != mwStatusRespond {
// No error, carry on...
meta["bypass"] = "1"
h.ServeHTTP(w, r)
}
job.TimingKv("exec_time", time.Since(startTime).Nanoseconds(), meta)
job.TimingKv(eventName+".exec_time", time.Since(startTime).Nanoseconds(), meta)
})
}
}
func AppendMiddleware(chain *[]alice.Constructor, mw TykMiddleware) {
if mw.IsEnabledForSpec() {
*chain = append(*chain, CreateMiddleware(mw))
}
}
func CheckCBEnabled(baseMid *BaseMiddleware) bool {
for _, v := range baseMid.Spec.VersionData.Versions {
if len(v.ExtendedPaths.CircuitBreaker) > 0 {
baseMid.Spec.CircuitBreakerEnabled = true
return true
}
}
return false
}
func CheckETEnabled(baseMid *BaseMiddleware) bool {
for _, v := range baseMid.Spec.VersionData.Versions {
if len(v.ExtendedPaths.HardTimeouts) > 0 {
baseMid.Spec.EnforcedTimeoutEnabled = true
return true
}
}
return false
}
type TykResponseHandler interface {
Init(interface{}, *APISpec) error
HandleResponse(http.ResponseWriter, *http.Response, *http.Request, *SessionState) error
}
func GetResponseProcessorByName(name string) (TykResponseHandler, error) {
switch name {
case "header_injector":
return &HeaderInjector{}, nil
case "response_body_transform":
return &ResponseTransformMiddleware{}, nil
case "header_transform":
return &HeaderTransform{}, nil
default:
return nil, errors.New("not found")
}
}
func handleResponseChain(chain []TykResponseHandler, rw http.ResponseWriter, res *http.Response, req *http.Request, ses *SessionState) error {
for _, rh := range chain {
if err := rh.HandleResponse(rw, res, req, ses); err != nil {
return err
}
}
return nil
}