<commit_before>package fileserver

import (
	"net/http"
	"strconv"

	"github.com/prasannavl/goerror/errutils"

	"github.com/prasannavl/goerror/httperror"
	"github.com/prasannavl/mchain"

	"github.com/prasannavl/go-gluons/log"
)

func New(root http.FileSystem) mchain.Handler {
	return &FileServer{root}
}

type FileServer struct {
	root http.FileSystem
}

func (f *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) error {
	return ServeRequestPath(w, r, f.root)
}

func NewEx(root http.FileSystem, notFoundHandler mchain.HandlerFunc) mchain.Handler {
	return &FileServerEx{FileServer{root}, true, notFoundHandler}
}

type FileServerEx struct {
	FileServer
	RedirectsEnabled bool
	NotFoundHandler  mchain.HandlerFunc
}

func (f *FileServerEx) ServeHTTP(w http.ResponseWriter, r *http.Request) error {
	err := ServeRequestPath(w, r, f.root)
	if err != nil {
		e := err.(*Err)

		l := log.With("path", r.URL.Path).
			With("status", e.Code())
		if !errutils.HasMessage(e) {
			l = l.With("cause", e.Cause())
		}
		switch e.Kind {
		case ErrRedirect:
			if f.RedirectsEnabled {
				e.Headers().Write(w)
				w.WriteHeader(http.StatusMovedPermanently)
				return nil
			}
		case ErrFsOpen:
			l.Warnf("fileserver: %v %v", e.Kind, e)
			if f.NotFoundHandler != nil {
				return f.NotFoundHandler(w, r)
			}
		default:
			l.Warnf("fileserver: %v %v", e.Kind, e)
		}
	}
	return err
}<commit_msg>change: switch to handler instead of func<commit_after>package fileserver

import (
	"net/http"
	"strconv"

	"github.com/prasannavl/goerror/errutils"

	"github.com/prasannavl/goerror/httperror"
	"github.com/prasannavl/mchain"

	"github.com/prasannavl/go-gluons/log"
)

func New(root http.FileSystem) mchain.Handler {
	return &FileServer{root}
}

type FileServer struct {
	root http.FileSystem
}

func (f *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) error {
	return ServeRequestPath(w, r, f.root)
}

func NewEx(root http.FileSystem, notFoundHandler mchain.Handler) mchain.Handler {
	return &FileServerEx{FileServer{root}, true, notFoundHandler}
}

type FileServerEx struct {
	FileServer
	RedirectsEnabled bool
	NotFoundHandler  mchain.Handler
}

func (f *FileServerEx) ServeHTTP(w http.ResponseWriter, r *http.Request) error {
	err := ServeRequestPath(w, r, f.root)
	if err != nil {
		e := err.(*Err)

		l := log.With("path", r.URL.Path).
			With("status", e.Code())
		if !errutils.HasMessage(e) {
			l = l.With("cause", e.Cause())
		}
		switch e.Kind {
		case ErrRedirect:
			if f.RedirectsEnabled {
				e.Headers().Write(w)
				w.WriteHeader(http.StatusMovedPermanently)
				return nil
			}
		case ErrFsOpen:
			l.Warnf("fileserver: %v %v", e.Kind, e)
			if f.NotFoundHandler != nil {
				return f.NotFoundHandler.ServeHTTP(w, r)
			}
		default:
			l.Warnf("fileserver: %v %v", e.Kind, e)
		}
	}
	return err
}
{'fraction_non_alphanumeric': 0.1372965322009908, 'fraction_numerical': 0.0, 'mean_word_length': 4.066308243727598, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2822392', 'n_tokens_mistral': 1170, 'n_tokens_neox': 1070, 'n_words': 222}