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 }