-
Notifications
You must be signed in to change notification settings - Fork 13
/
main.go
116 lines (96 loc) · 3.03 KB
/
main.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
package main
import (
"crypto/subtle"
"flag"
"log"
"net/http"
"regexp"
"time"
"github.com/valyala/fasthttp"
"github.com/zerodha/fastglue"
)
var (
addr = flag.String("addr", ":8080", "TCP address to listen to")
)
func main() {
flag.Parse()
g := fastglue.New()
g.GET("/", auth(validateAll(handleGetAll)))
g.PUT("/", auth(fastglue.ReqLenParams(validate(handleMiddleware), map[string]int{"a": 5, "b": 5})))
g.POST("/", auth(fastglue.ReqParams(validate(handleMiddleware), []string{"a", "b"})))
s := &fasthttp.Server{
Name: "Middleware",
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
}
if err := g.ListenAndServe(*addr, "", s); err != nil {
log.Fatalf("Error in ListenAndServe: %s", err)
}
}
var (
rxAlphaNum = regexp.MustCompile("^([a-zA-Z0-9])+$")
rxAlphaNumLen = regexp.MustCompile("^[a-zA-Z0-9]{4,100}$")
)
func isAlphanum(input string) bool {
return rxAlphaNum.MatchString(input)
}
func isAlphanumLen(input string) bool {
return rxAlphaNumLen.MatchString(input)
}
func validate(h fastglue.FastRequestHandler) fastglue.FastRequestHandler {
return func(r *fastglue.Request) error {
a := string(r.RequestCtx.PostArgs().Peek("a"))
b := string(r.RequestCtx.PostArgs().Peek("b"))
if !isAlphanum(a) || !isAlphanum(b) {
return r.SendErrorEnvelope(http.StatusBadRequest, "validation failed", nil, "ValidationError")
}
return h(r)
}
}
func validateAll(h fastglue.FastRequestHandler) fastglue.FastRequestHandler {
return func(r *fastglue.Request) error {
var invalid bool
r.RequestCtx.QueryArgs().VisitAll(func(k, v []byte) {
if !isAlphanum(string(k)) || !isAlphanumLen(string(v)) {
invalid = true
}
})
if invalid {
return r.SendErrorEnvelope(http.StatusBadRequest, "validation failed", nil, "ValidationError")
}
return h(r)
}
}
func handleMiddleware(r *fastglue.Request) error {
var out = map[string]interface{}{
"a": string(r.RequestCtx.PostArgs().Peek("a")),
"b": string(r.RequestCtx.PostArgs().Peek("b")),
}
return r.SendEnvelope(out)
}
func handleGetAll(r *fastglue.Request) error {
var out = map[string]interface{}{"name": "fastglue"}
r.RequestCtx.QueryArgs().VisitAll(func(k, v []byte) {
out[string(k)] = string(v)
})
return r.SendJSON(http.StatusOK, out)
}
var (
username = []byte("admin")
password = []byte("pass")
realm = "Please enter your username and password for this site"
)
func auth(h fastglue.FastRequestHandler) fastglue.FastRequestHandler {
return func(r *fastglue.Request) error {
un, pw, err := r.ParseAuthHeader(fastglue.AuthBasic)
if err != nil {
r.RequestCtx.Response.Header.Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
return r.SendBytes(http.StatusUnauthorized, fastglue.PLAINTEXT, []byte("Unauthorizaed\n"))
}
if subtle.ConstantTimeCompare(un, []byte(username)) != 1 || subtle.ConstantTimeCompare(pw, []byte(password)) != 1 {
r.RequestCtx.Response.Header.Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
return r.SendBytes(http.StatusUnauthorized, fastglue.PLAINTEXT, []byte("Unauthorizaed\n"))
}
return h(r)
}
}