2015-03-19 16:37:16 -04:00
// largely adapted from https://github.com/gorilla/handlers/blob/master/handlers.go
// to add logging of request duration as last value (and drop referrer)
package main
import (
2019-04-12 09:26:44 -07:00
"bufio"
"errors"
"net"
2015-03-19 16:37:16 -04:00
"net/http"
"time"
2020-03-29 14:54:36 +01:00
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
2017-07-14 13:08:34 +02:00
)
2015-03-19 16:37:16 -04:00
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
// code and body size
type responseLogger struct {
w http . ResponseWriter
status int
size int
upstream string
authInfo string
}
2018-12-20 09:30:42 +00:00
// Header returns the ResponseWriter's Header
2015-03-19 16:37:16 -04:00
func ( l * responseLogger ) Header ( ) http . Header {
return l . w . Header ( )
}
2019-03-22 17:19:38 -04:00
// Support Websocket
func ( l * responseLogger ) Hijack ( ) ( rwc net . Conn , buf * bufio . ReadWriter , err error ) {
if hj , ok := l . w . ( http . Hijacker ) ; ok {
return hj . Hijack ( )
}
return nil , nil , errors . New ( "http.Hijacker is not available on writer" )
}
2018-12-20 09:30:42 +00:00
// ExtractGAPMetadata extracts and removes GAP headers from the ResponseWriter's
// Header
2015-03-19 16:37:16 -04:00
func ( l * responseLogger ) ExtractGAPMetadata ( ) {
upstream := l . w . Header ( ) . Get ( "GAP-Upstream-Address" )
if upstream != "" {
l . upstream = upstream
l . w . Header ( ) . Del ( "GAP-Upstream-Address" )
}
authInfo := l . w . Header ( ) . Get ( "GAP-Auth" )
if authInfo != "" {
l . authInfo = authInfo
l . w . Header ( ) . Del ( "GAP-Auth" )
}
}
2018-12-20 09:30:42 +00:00
// Write writes the response using the ResponseWriter
2015-03-19 16:37:16 -04:00
func ( l * responseLogger ) Write ( b [ ] byte ) ( int , error ) {
if l . status == 0 {
// The status will be StatusOK if WriteHeader has not been called yet
l . status = http . StatusOK
}
l . ExtractGAPMetadata ( )
size , err := l . w . Write ( b )
l . size += size
return size , err
}
2018-12-20 09:30:42 +00:00
// WriteHeader writes the status code for the Response
2015-03-19 16:37:16 -04:00
func ( l * responseLogger ) WriteHeader ( s int ) {
l . ExtractGAPMetadata ( )
l . w . WriteHeader ( s )
l . status = s
}
2018-12-20 09:30:42 +00:00
// Status returns the response status code
2015-03-19 16:37:16 -04:00
func ( l * responseLogger ) Status ( ) int {
return l . status
}
2019-05-31 20:11:28 +12:00
// Size returns the response size
2015-03-19 16:37:16 -04:00
func ( l * responseLogger ) Size ( ) int {
return l . size
}
2019-05-31 20:11:28 +12:00
// Flush sends any buffered data to the client
2019-01-31 14:02:15 +00:00
func ( l * responseLogger ) Flush ( ) {
if flusher , ok := l . w . ( http . Flusher ) ; ok {
flusher . Flush ( )
}
}
2019-05-31 20:11:28 +12:00
// loggingHandler is the http.Handler implementation for LoggingHandler
2015-03-19 16:37:16 -04:00
type loggingHandler struct {
2019-02-10 08:37:45 -08:00
handler http . Handler
2015-03-19 16:37:16 -04:00
}
2018-12-20 09:30:42 +00:00
// LoggingHandler provides an http.Handler which logs requests to the HTTP server
2019-02-10 08:37:45 -08:00
func LoggingHandler ( h http . Handler ) http . Handler {
2017-07-14 13:08:34 +02:00
return loggingHandler {
2019-02-10 08:37:45 -08:00
handler : h ,
2017-07-14 13:08:34 +02:00
}
2015-03-19 16:37:16 -04:00
}
func ( h loggingHandler ) ServeHTTP ( w http . ResponseWriter , req * http . Request ) {
t := time . Now ( )
url := * req . URL
2019-02-10 08:37:45 -08:00
responseLogger := & responseLogger { w : w }
h . handler . ServeHTTP ( responseLogger , req )
logger . PrintReq ( responseLogger . authInfo , responseLogger . upstream , req , url , t , responseLogger . Status ( ) , responseLogger . Size ( ) )
2015-03-19 16:37:16 -04:00
}