Commit 34436d11e24884e190b5addb8fb575ad2676eb3f
1 parent
932f814613
Exists in
master
and in
1 other branch
in-out http logs are written at the same time
Showing
2 changed files
with
29 additions
and
7 deletions
Show diff stats
http.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/json" | 4 | "encoding/json" |
5 | "fmt" | 5 | "fmt" |
6 | "net/http" | 6 | "net/http" |
7 | ) | 7 | ) |
8 | 8 | ||
9 | type ResponseWriterStatusRecorder struct { | ||
10 | http.ResponseWriter | ||
11 | status int | ||
12 | } | ||
13 | |||
14 | func WrapWithStatusRecorder(w http.ResponseWriter) *ResponseWriterStatusRecorder { | ||
15 | return &ResponseWriterStatusRecorder{w, 0} | ||
16 | } | ||
17 | |||
18 | func (r *ResponseWriterStatusRecorder) WriteHeader(code int) { | ||
19 | r.status = code | ||
20 | r.ResponseWriter.WriteHeader(code) | ||
21 | } | ||
22 | |||
23 | func (r *ResponseWriterStatusRecorder) Status() int { | ||
24 | return r.status | ||
25 | } | ||
26 | |||
9 | // NotFoundHandlerFunc writes HTTP error 404 to w. | 27 | // NotFoundHandlerFunc writes HTTP error 404 to w. |
10 | func NotFoundHandlerFunc(w http.ResponseWriter, req *http.Request) { | 28 | func NotFoundHandlerFunc(w http.ResponseWriter, req *http.Request) { |
11 | SetDefaultHeaders(w) | 29 | SetDefaultHeaders(w) |
12 | if req.Method == "OPTIONS" { | 30 | if req.Method == "OPTIONS" { |
13 | return | 31 | return |
14 | } | 32 | } |
15 | NotFound(w, req, fmt.Sprintf("Resource you requested was not found: %s", req.URL.String())) | 33 | NotFound(w, req, fmt.Sprintf("Resource you requested was not found: %s", req.URL.String())) |
16 | } | 34 | } |
17 | 35 | ||
18 | // SetDefaultHeaders set's default headers for an HTTP response. | 36 | // SetDefaultHeaders set's default headers for an HTTP response. |
19 | func SetDefaultHeaders(w http.ResponseWriter) { | 37 | func SetDefaultHeaders(w http.ResponseWriter) { |
20 | w.Header().Set("Access-Control-Allow-Origin", "*") | 38 | w.Header().Set("Access-Control-Allow-Origin", "*") |
21 | w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS") | 39 | w.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS") |
22 | w.Header().Set("Access-Control-Allow-Headers", `Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization`) | 40 | w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") |
23 | w.Header().Set("Content-Type", "application/json; charset=utf-8") | 41 | w.Header().Set("Content-Type", "application/json; charset=utf-8") |
24 | } | 42 | } |
25 | 43 | ||
26 | func ReqLocale(req *http.Request, dflt string) string { | 44 | func GetLocale(req *http.Request, dflt string) string { |
27 | loc := req.FormValue("locale") | 45 | loc := req.FormValue("locale") |
28 | if loc == "" { | 46 | if loc == "" { |
29 | return dflt | 47 | return dflt |
30 | } | 48 | } |
31 | return loc | 49 | return loc |
32 | } | 50 | } |
33 | 51 | ||
34 | // 2xx | 52 | // 2xx |
35 | func Success(w http.ResponseWriter, payload interface{}, code int) { | 53 | func Success(w http.ResponseWriter, payload interface{}, code int) { |
36 | w.WriteHeader(code) | 54 | w.WriteHeader(code) |
37 | if payload != nil { | 55 | if payload != nil { |
38 | json.NewEncoder(w).Encode(payload) | 56 | json.NewEncoder(w).Encode(payload) |
39 | } | 57 | } |
40 | } | 58 | } |
41 | 59 | ||
42 | // 200 | 60 | // 200 |
43 | func OK(w http.ResponseWriter, payload interface{}) { | 61 | func OK(w http.ResponseWriter, payload interface{}) { |
44 | Success(w, payload, http.StatusOK) | 62 | Success(w, payload, http.StatusOK) |
45 | } | 63 | } |
46 | 64 | ||
47 | // 201 | 65 | // 201 |
48 | func Created(w http.ResponseWriter, payload interface{}) { | 66 | func Created(w http.ResponseWriter, payload interface{}) { |
49 | Success(w, payload, http.StatusCreated) | 67 | Success(w, payload, http.StatusCreated) |
50 | } | 68 | } |
51 | 69 | ||
52 | type weberror struct { | 70 | type weberror struct { |
53 | Request string `json:"request"` | 71 | Request string `json:"request"` |
54 | Error string `json:"error"` | 72 | Error string `json:"error"` |
55 | } | 73 | } |
56 | 74 | ||
57 | // 4xx; 5xx | 75 | // 4xx; 5xx |
58 | func Error(w http.ResponseWriter, r *http.Request, code int, err string) { | 76 | func Error(w http.ResponseWriter, r *http.Request, code int, err string) { |
59 | werr := weberror{Error: err, Request: r.Method + " " + r.RequestURI} | 77 | werr := weberror{Error: err, Request: r.Method + " " + r.RequestURI} |
60 | w.WriteHeader(code) | 78 | w.WriteHeader(code) |
61 | json.NewEncoder(w).Encode(werr) | 79 | json.NewEncoder(w).Encode(werr) |
62 | } | 80 | } |
63 | 81 | ||
64 | // 400 | 82 | // 400 |
65 | func BadRequest(w http.ResponseWriter, r *http.Request, err string) { | 83 | func BadRequest(w http.ResponseWriter, r *http.Request, err string) { |
66 | Error(w, r, http.StatusBadRequest, err) | 84 | Error(w, r, http.StatusBadRequest, err) |
67 | } | 85 | } |
68 | 86 | ||
69 | // 401 | 87 | // 401 |
70 | func Unauthorized(w http.ResponseWriter, r *http.Request, err string) { | 88 | func Unauthorized(w http.ResponseWriter, r *http.Request, err string) { |
71 | Error(w, r, http.StatusUnauthorized, err) | 89 | Error(w, r, http.StatusUnauthorized, err) |
72 | } | 90 | } |
73 | 91 | ||
74 | // 403 | 92 | // 403 |
75 | func Forbidden(w http.ResponseWriter, r *http.Request, err string) { | 93 | func Forbidden(w http.ResponseWriter, r *http.Request, err string) { |
76 | Error(w, r, http.StatusForbidden, err) | 94 | Error(w, r, http.StatusForbidden, err) |
77 | } | 95 | } |
78 | 96 | ||
79 | // 404 | 97 | // 404 |
80 | func NotFound(w http.ResponseWriter, r *http.Request, err string) { | 98 | func NotFound(w http.ResponseWriter, r *http.Request, err string) { |
81 | Error(w, r, http.StatusNotFound, err) | 99 | Error(w, r, http.StatusNotFound, err) |
82 | } | 100 | } |
83 | 101 | ||
84 | // 409 | 102 | // 409 |
85 | func Conflict(w http.ResponseWriter, r *http.Request, err string) { | 103 | func Conflict(w http.ResponseWriter, r *http.Request, err string) { |
86 | Error(w, r, http.StatusConflict, err) | 104 | Error(w, r, http.StatusConflict, err) |
87 | } | 105 | } |
88 | 106 | ||
89 | // 500 | 107 | // 500 |
90 | func InternalServerError(w http.ResponseWriter, r *http.Request, err string) { | 108 | func InternalServerError(w http.ResponseWriter, r *http.Request, err string) { |
91 | Error(w, r, http.StatusInternalServerError, err) | 109 | Error(w, r, http.StatusInternalServerError, err) |
92 | } | 110 | } |
93 | 111 |
middleware.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "net/http" | 4 | "net/http" |
5 | "time" | 5 | "time" |
6 | 6 | ||
7 | "git.to-net.rs/marko.tikvic/gologger" | 7 | "git.to-net.rs/marko.tikvic/gologger" |
8 | ) | 8 | ) |
9 | 9 | ||
10 | func SetHeaders(h http.HandlerFunc) http.HandlerFunc { | 10 | func SetHeaders(h http.HandlerFunc) http.HandlerFunc { |
11 | return func(w http.ResponseWriter, req *http.Request) { | 11 | return func(w http.ResponseWriter, req *http.Request) { |
12 | SetDefaultHeaders(w) | 12 | SetDefaultHeaders(w) |
13 | if req.Method == http.MethodOptions { | 13 | if req.Method == http.MethodOptions { |
14 | return | 14 | return |
15 | } | 15 | } |
16 | h(w, req) | 16 | h(w, req) |
17 | } | 17 | } |
18 | } | 18 | } |
19 | 19 | ||
20 | func ParseForm(h http.HandlerFunc) http.HandlerFunc { | 20 | func ParseForm(h http.HandlerFunc) http.HandlerFunc { |
21 | return func(w http.ResponseWriter, req *http.Request) { | 21 | return func(w http.ResponseWriter, req *http.Request) { |
22 | err := req.ParseForm() | 22 | err := req.ParseForm() |
23 | if err != nil { | 23 | if err != nil { |
24 | BadRequest(w, req, err.Error()) | 24 | BadRequest(w, req, err.Error()) |
25 | return | 25 | return |
26 | } | 26 | } |
27 | h(w, req) | 27 | h(w, req) |
28 | } | 28 | } |
29 | } | 29 | } |
30 | 30 | ||
31 | var reqLogger *gologger.Logger | 31 | var trafficLogger *gologger.Logger |
32 | 32 | ||
33 | func EnableLogging(log string) error { | 33 | func EnableLogging(log string) error { |
34 | var err error | 34 | var err error |
35 | reqLogger, err = gologger.New(log, gologger.MaxLogSize5MB) | 35 | trafficLogger, err = gologger.New(log, gologger.MaxLogSize5MB) |
36 | return err | 36 | return err |
37 | } | 37 | } |
38 | 38 | ||
39 | func Log(h http.HandlerFunc) http.HandlerFunc { | 39 | func Log(h http.HandlerFunc) http.HandlerFunc { |
40 | return func(w http.ResponseWriter, req *http.Request) { | 40 | return func(w http.ResponseWriter, req *http.Request) { |
41 | reqLogger.LogRequest(req, "") | 41 | in := trafficLogger.RequestLog(req, "") |
42 | |||
43 | w2 := WrapWithStatusRecorder(w) | ||
42 | t1 := time.Now() | 44 | t1 := time.Now() |
43 | h(w, req) | 45 | h(w2, req) |
44 | t2 := time.Now() | 46 | t2 := time.Now() |
45 | reqLogger.LogResponse(w, req, t2.Sub(t1)) | 47 | |
48 | out := trafficLogger.ResponseLog(w2.Status(), t2.Sub(t1)) | ||
49 | trafficLogger.LogHTTPTraffic(in, out) | ||
46 | } | 50 | } |
47 | } | 51 | } |
48 | 52 | ||
49 | func Auth(roles string, h http.HandlerFunc) http.HandlerFunc { | 53 | func Auth(roles string, h http.HandlerFunc) http.HandlerFunc { |
50 | return func(w http.ResponseWriter, req *http.Request) { | 54 | return func(w http.ResponseWriter, req *http.Request) { |
51 | if _, ok := AuthCheck(req, roles); !ok { | 55 | if _, ok := AuthCheck(req, roles); !ok { |
52 | Unauthorized(w, req, "") | 56 | Unauthorized(w, req, "") |
53 | return | 57 | return |
54 | } | 58 | } |
55 | h(w, req) | 59 | h(w, req) |
56 | } | 60 | } |
57 | } | 61 | } |
58 | 62 |