github.com/gocaveman/caveman@v0.0.0-20191211162744-0ddf99dbdf6e/webutil/http-server.go (about)

     1  package webutil
     2  
     3  import (
     4  	"context"
     5  	"log"
     6  	"net/http"
     7  	"os"
     8  	"path"
     9  	"sync"
    10  )
    11  
    12  // hm, this becomes circular... blarg...  maybe it belongs in handlerregistry...
    13  // func init() {
    14  // 	handlerregistry.MustRegister(handlerregistry.SeqSetup, "RequestContextHandler", NewRequestContextHandler())
    15  // }
    16  
    17  // StartHTTPServer is a very simple helper that starts an http.Server.
    18  // The WaitGroup.Add(1) and Done are called at the appropriate times
    19  // and logging is done.  This is just to help make projects' main.go
    20  // more concise and easier to read.
    21  func StartHTTPServer(s *http.Server, wg *sync.WaitGroup) {
    22  	wg.Add(1)
    23  	log.Printf("Listening for HTTP at %q", s.Addr)
    24  	go func() {
    25  		defer wg.Done()
    26  		err := s.ListenAndServe()
    27  		if err != nil {
    28  			log.Printf("Error from HTTP server: %v", err)
    29  		}
    30  	}()
    31  }
    32  
    33  // NewRequestContextHandler returns a handler that sets "http.Request"
    34  // in the context.  Intended for use in HTML templates for things like
    35  // getting URL params.
    36  func NewRequestContextHandler() ChainHandler {
    37  	return ChainHandlerFunc(func(w http.ResponseWriter, r *http.Request) (wnext http.ResponseWriter, rnext *http.Request) {
    38  		return w, r.WithContext(context.WithValue(r.Context(), "http.Request", r))
    39  	})
    40  }
    41  
    42  // NewStaticFileHandler returns a handler similar to the stdlib FileServer.
    43  // The primary difference is that instead of returning an error if the file
    44  // is not found it will instead not serve anything (so the request will
    45  // fall through to the next handler in the chain).  It also sets the cache-control
    46  // header (only if not already set) to tell the browser to not cache if no
    47  // query string or to cache for one week if query string.  Provides an easy way
    48  // to control which files are cached by the browser with the default to not cache
    49  // them.  This handler will ignore directories and take no action if one is found.
    50  func NewStaticFileHandler(fs http.FileSystem) http.Handler {
    51  
    52  	fsh := http.FileServer(fs)
    53  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    54  		p := path.Clean("/" + r.URL.Path)
    55  		f, err := fs.Open(p)
    56  		if err == nil {
    57  			defer f.Close()
    58  			st, err := f.Stat()
    59  			if err != nil {
    60  				HTTPError(w, r, err, "Error inspecting file.", 500)
    61  				return
    62  			}
    63  			if st.IsDir() {
    64  				return
    65  			}
    66  
    67  			cc := w.Header().Get("cache-control")
    68  			if cc == "" {
    69  				if r.URL.RawQuery == "" {
    70  					w.Header().Set("cache-control", "no-cache")
    71  				} else {
    72  					w.Header().Set("cache-control", "max-age=604800")
    73  				}
    74  			}
    75  
    76  			fsh.ServeHTTP(w, r)
    77  		} else {
    78  			// differentiate here between a file that doesn't exist an something else wrong with the filesystem
    79  			if !os.IsNotExist(err) {
    80  				HTTPError(w, r, err, "Error serving file.", 500)
    81  				return
    82  			}
    83  		}
    84  	})
    85  
    86  }