git.iko.soy/typeable/oauth2-proxy
on ea261ca help sign in
110 lines 2.7 kB history raw
1package middleware
3import (
4 "bufio"
5 "errors"
6 "net"
7 "net/http"
8 "time"
10 "github.com/justinas/alice"
11 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
12 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
15// NewRequestLogger returns middleware which logs requests
16// It uses a custom ResponseWriter to track status code & response size details
17func NewRequestLogger() alice.Constructor {
18 return requestLogger
21func requestLogger(next http.Handler) http.Handler {
22 return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
23 startTime := time.Now()
24 url := *req.URL
26 responseLogger := &loggingResponse{ResponseWriter: rw}
27 next.ServeHTTP(responseLogger, req)
29 scope := middlewareapi.GetRequestScope(req)
30 // If scope is nil, this will panic.
31 // A scope should always be injected before this handler is called.
32 logger.PrintReq(
33 getUser(scope),
34 scope.Upstream,
35 req,
36 url,
37 startTime,
38 responseLogger.Status(),
39 responseLogger.Size(),
40 )
41 })
44func getUser(scope *middlewareapi.RequestScope) string {
45 session := scope.Session
46 if session != nil {
47 if session.Email != "" {
48 return session.Email
49 }
50 return session.User
51 }
52 return ""
55// loggingResponse is a custom http.ResponseWriter that allows tracking certain
56// details for request logging.
57type loggingResponse struct {
58 http.ResponseWriter
60 status int
61 size int
64// Write writes the response using the ResponseWriter
65func (r *loggingResponse) Write(b []byte) (int, error) {
66 if r.status == 0 {
67 // The status will be StatusOK if WriteHeader has not been called yet
68 r.status = http.StatusOK
69 }
70 size, err := r.ResponseWriter.Write(b)
71 r.size += size
72 return size, err
75// WriteHeader writes the status code for the Response
76func (r *loggingResponse) WriteHeader(s int) {
77 r.ResponseWriter.WriteHeader(s)
78 r.status = s
81// Hijack implements the `http.Hijacker` interface that actual ResponseWriters
82// implement to support websockets
83func (r *loggingResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
84 if hj, ok := r.ResponseWriter.(http.Hijacker); ok {
85 return hj.Hijack()
86 }
87 return nil, nil, errors.New("http.Hijacker is not available on writer")
90// Flush sends any buffered data to the client. Implements the `http.Flusher`
91// interface
92func (r *loggingResponse) Flush() {
93 if flusher, ok := r.ResponseWriter.(http.Flusher); ok {
94 if r.status == 0 {
95 // The status will be StatusOK if WriteHeader has not been called yet
96 r.status = http.StatusOK
97 }
98 flusher.Flush()
99 }
102// Status returns the response status code
103func (r *loggingResponse) Status() int {
104 return r.status
107// Size returns the response size
108func (r *loggingResponse) Size() int {
109 return r.size