github.com/influx6/npkg@v0.8.8/nhttp/filesystem.go (about)

     1  package nhttp
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"io"
     7  	"net/http"
     8  	"path"
     9  	"strings"
    10  
    11  	filesystem "github.com/influx6/npkg/nfs"
    12  )
    13  
    14  // GzipServe returns a Handler which handles the necessary bits to gzip or ungzip
    15  // file resonses from a http.FileSystem.
    16  func GzipServe(fs filesystem.FileSystem, gzipped bool) ContextHandler {
    17  	return func(ctx *Ctx) error {
    18  		reqURL := path.Clean(ctx.Path())
    19  		if reqURL == "./" || reqURL == "." {
    20  			ctx.Redirect(http.StatusMovedPermanently, "/")
    21  			return nil
    22  		}
    23  
    24  		if !strings.HasPrefix(reqURL, "/") {
    25  			reqURL = "/" + reqURL
    26  		}
    27  
    28  		file, err := fs.Open(reqURL)
    29  		if err != nil {
    30  			return err
    31  		}
    32  
    33  		stat, err := file.Stat()
    34  		if err != nil {
    35  			return err
    36  		}
    37  
    38  		mime := GetFileMimeType(stat.Name())
    39  		ctx.AddHeader("Content-Type", mime)
    40  
    41  		if ctx.HasHeader("Accept-Encoding", "gzip") && gzipped {
    42  			ctx.SetHeader("Content-Encoding", "gzip")
    43  			defer ctx.Status(http.StatusOK)
    44  			http.ServeContent(ctx.Response(), ctx.Request(), stat.Name(), stat.ModTime(), file)
    45  			return nil
    46  		}
    47  
    48  		if ctx.HasHeader("Accept-Encoding", "gzip") && !gzipped {
    49  			ctx.SetHeader("Content-Encoding", "gzip")
    50  
    51  			gwriter := gzip.NewWriter(ctx.Response())
    52  			defer gwriter.Close()
    53  
    54  			_, err := io.Copy(gwriter, file)
    55  			if err != nil && err != io.EOF {
    56  				return err
    57  			}
    58  
    59  			ctx.Status(http.StatusOK)
    60  
    61  			return nil
    62  		}
    63  
    64  		if !ctx.HasHeader("Accept-Encoding", "gzip") && gzipped {
    65  			gzreader, err := gzip.NewReader(file)
    66  			if err != nil {
    67  				return err
    68  			}
    69  
    70  			var bu bytes.Buffer
    71  			_, err = io.Copy(&bu, gzreader)
    72  			if err != nil && err != io.EOF {
    73  				return err
    74  			}
    75  
    76  			defer ctx.Status(http.StatusOK)
    77  			http.ServeContent(ctx.Response(), ctx.Request(), stat.Name(), stat.ModTime(), bytes.NewReader(bu.Bytes()))
    78  			return nil
    79  		}
    80  
    81  		defer ctx.Status(http.StatusOK)
    82  		http.ServeContent(ctx.Response(), ctx.Request(), stat.Name(), stat.ModTime(), file)
    83  		return nil
    84  	}
    85  }
    86  
    87  // HTTPGzipServer returns a http.Handler which handles the necessary bits to gzip or ungzip
    88  // file resonses from a http.FileSystem.
    89  func HTTPGzipServer(fs http.FileSystem, gzipped bool) http.Handler {
    90  	zipper := HTTPGzipServe(fs, gzipped)
    91  	return handlerImpl{ContextHandler: zipper}
    92  }
    93  
    94  // HTTPGzipServe returns a Handler which handles the necessary bits to gzip or ungzip
    95  // file resonses from a http.FileSystem.
    96  func HTTPGzipServe(fs http.FileSystem, gzipped bool) ContextHandler {
    97  	return func(ctx *Ctx) error {
    98  		reqURL := path.Clean(ctx.Path())
    99  		if reqURL == "./" || reqURL == "." {
   100  			ctx.Redirect(http.StatusMovedPermanently, "/")
   101  			return nil
   102  		}
   103  
   104  		if !strings.HasPrefix(reqURL, "/") {
   105  			reqURL = "/" + reqURL
   106  		}
   107  
   108  		file, err := fs.Open(reqURL)
   109  		if err != nil {
   110  			return err
   111  		}
   112  
   113  		stat, err := file.Stat()
   114  		if err != nil {
   115  			return err
   116  		}
   117  
   118  		mime := GetFileMimeType(stat.Name())
   119  		ctx.AddHeader("Content-Type", mime)
   120  
   121  		if ctx.HasHeader("Accept-Encoding", "gzip") && gzipped {
   122  			ctx.SetHeader("Content-Encoding", "gzip")
   123  			defer ctx.Status(http.StatusOK)
   124  			http.ServeContent(ctx.Response(), ctx.Request(), stat.Name(), stat.ModTime(), file)
   125  			return nil
   126  		}
   127  
   128  		if ctx.HasHeader("Accept-Encoding", "gzip") && !gzipped {
   129  			ctx.SetHeader("Content-Encoding", "gzip")
   130  
   131  			gwriter := gzip.NewWriter(ctx.Response())
   132  			defer gwriter.Close()
   133  
   134  			_, err := io.Copy(gwriter, file)
   135  			if err != nil && err != io.EOF {
   136  				return err
   137  			}
   138  
   139  			ctx.Status(http.StatusOK)
   140  
   141  			return nil
   142  		}
   143  
   144  		if !ctx.HasHeader("Accept-Encoding", "gzip") && gzipped {
   145  			gzreader, err := gzip.NewReader(file)
   146  			if err != nil {
   147  				return err
   148  			}
   149  
   150  			var bu bytes.Buffer
   151  			_, err = io.Copy(&bu, gzreader)
   152  			if err != nil && err != io.EOF {
   153  				return err
   154  			}
   155  
   156  			defer ctx.Status(http.StatusOK)
   157  			http.ServeContent(ctx.Response(), ctx.Request(), stat.Name(), stat.ModTime(), bytes.NewReader(bu.Bytes()))
   158  			return nil
   159  		}
   160  
   161  		defer ctx.Status(http.StatusOK)
   162  		http.ServeContent(ctx.Response(), ctx.Request(), stat.Name(), stat.ModTime(), file)
   163  		return nil
   164  	}
   165  }