Catch all other missing request patterns to logs
This commit is contained in:
@@ -48,6 +48,23 @@ func isTLSError(err error) bool {
|
||||
return strings.HasPrefix(err.Error(), "tls:")
|
||||
}
|
||||
|
||||
// withStatusLogging wraps a handler to log 404 and 405 responses.
|
||||
func withStatusLogging(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rw := &responseWriterWrapper{ResponseWriter: w, statusCode: http.StatusOK}
|
||||
next.ServeHTTP(rw, r)
|
||||
|
||||
clientIP := getClientIP(r)
|
||||
|
||||
switch rw.statusCode {
|
||||
case http.StatusNotFound:
|
||||
log.Infof("Not Found from %s to %s", clientIP, r.RequestURI)
|
||||
case http.StatusMethodNotAllowed:
|
||||
log.Infof("Method Not Allowed from %s for %s %s", clientIP, r.Method, r.RequestURI)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// withServerHeader wraps a handler to add Server header to all responses.
|
||||
func withServerHeader(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -74,6 +91,13 @@ func NewServer(configPath string) (*ServerWrapper, error) {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
backupHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
// Only GET method is allowed.
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
username, password, ok := r.BasicAuth()
|
||||
|
||||
// No auth? Good bye.
|
||||
@@ -219,7 +243,7 @@ func NewServer(configPath string) (*ServerWrapper, error) {
|
||||
srv := &ServerWrapper{
|
||||
Server: &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", C.Address, C.Port),
|
||||
Handler: withServerHeader(mux),
|
||||
Handler: withServerHeader(withStatusLogging(mux)),
|
||||
ReadHeaderTimeout: readHeaderTimeout,
|
||||
WriteTimeout: time.Duration(C.BackupTimeout) * time.Minute,
|
||||
IdleTimeout: idleTimeout,
|
||||
@@ -235,7 +259,7 @@ func NewServer(configPath string) (*ServerWrapper, error) {
|
||||
srv := &ServerWrapper{
|
||||
Server: &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", C.Address, C.Port),
|
||||
Handler: withServerHeader(mux),
|
||||
Handler: withServerHeader(withStatusLogging(mux)),
|
||||
ReadHeaderTimeout: readHeaderTimeout,
|
||||
WriteTimeout: time.Duration(C.BackupTimeout) * time.Minute,
|
||||
IdleTimeout: idleTimeout,
|
||||
@@ -374,8 +398,20 @@ type (
|
||||
ServerWrapper struct {
|
||||
*http.Server
|
||||
}
|
||||
|
||||
// responseWriterWrapper wraps http.ResponseWriter to capture status code.
|
||||
responseWriterWrapper struct {
|
||||
http.ResponseWriter
|
||||
statusCode int
|
||||
}
|
||||
)
|
||||
|
||||
// WriteHeader captures the status code for logging.
|
||||
func (rw *responseWriterWrapper) WriteHeader(code int) {
|
||||
rw.statusCode = code
|
||||
rw.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
// Serve starts the server and classifies any errors returned.
|
||||
// TLS-related errors are logged at debug level, other errors at warn level.
|
||||
func (sw *ServerWrapper) Serve() error {
|
||||
|
||||
@@ -523,4 +523,99 @@ func TestCopyWithContextCancellation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStatusLogging404 tests that 404 responses are logged.
|
||||
func TestStatusLogging404(t *testing.T) {
|
||||
C = Config{} // Reset global config.
|
||||
excludePatterns = nil
|
||||
|
||||
// Create a minimal mux that returns 404 for all paths
|
||||
testMux := http.NewServeMux()
|
||||
testMux.HandleFunc("/archive", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
|
||||
wrappedMux := withStatusLogging(testMux)
|
||||
|
||||
// Use a ResponseRecorder to capture the response
|
||||
rr := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/nonexistent", nil)
|
||||
req.RemoteAddr = "127.0.0.1:12345"
|
||||
|
||||
wrappedMux.ServeHTTP(rr, req)
|
||||
|
||||
if rr.Code != http.StatusNotFound {
|
||||
t.Errorf("Expected status 404, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestStatusLogging405 tests that 405 responses are logged.
|
||||
func TestStatusLogging405(t *testing.T) {
|
||||
C = Config{} // Reset global config.
|
||||
excludePatterns = nil
|
||||
|
||||
// Create a minimal mux that returns 405 for wrong method
|
||||
testMux := http.NewServeMux()
|
||||
testMux.HandleFunc("/archive", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
})
|
||||
|
||||
wrappedMux := withStatusLogging(testMux)
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/archive", nil)
|
||||
req.RemoteAddr = "127.0.0.1:12345"
|
||||
|
||||
wrappedMux.ServeHTTP(rr, req)
|
||||
|
||||
if rr.Code != http.StatusMethodNotAllowed {
|
||||
t.Errorf("Expected status 405, got %d", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMethodNotAllowedHandler tests that non-GET methods return 405.
|
||||
func TestMethodNotAllowedHandler(t *testing.T) {
|
||||
C = Config{
|
||||
Address: "0.0.0.0",
|
||||
Port: 8086,
|
||||
Location: "/archive",
|
||||
User: "testuser",
|
||||
Password: "testpass",
|
||||
Directories: []string{"../../test_data/test1/foo"},
|
||||
}
|
||||
excludePatterns = nil
|
||||
|
||||
// Create test server
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok || username != C.User || password != C.Password {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method != http.MethodGet {
|
||||
w.Header().Set("Server", "backer")
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
// Test POST method
|
||||
req, _ := http.NewRequest("POST", server.URL+"/archive", nil)
|
||||
req.SetBasicAuth("testuser", "testpass")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Request failed: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusMethodNotAllowed {
|
||||
t.Errorf("Expected status 405, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
/* vim: setlocal ft=go noet ai ts=4 sw=4 sts=4: */
|
||||
|
||||
Reference in New Issue
Block a user