beego: move staticServer to New file
Showing
3 changed files
with
124 additions
and
139 deletions
| ... | @@ -14,12 +14,12 @@ import ( | ... | @@ -14,12 +14,12 @@ import ( |
| 14 | "time" | 14 | "time" |
| 15 | ) | 15 | ) |
| 16 | 16 | ||
| 17 | var gmfim map[string]*MemFileInfo = make(map[string]*MemFileInfo) | 17 | var gmfim map[string]*memFileInfo = make(map[string]*memFileInfo) |
| 18 | var lock sync.RWMutex | 18 | var lock sync.RWMutex |
| 19 | 19 | ||
| 20 | // OpenMemZipFile returns MemFile object with a compressed static file. | 20 | // OpenMemZipFile returns MemFile object with a compressed static file. |
| 21 | // it's used for serve static file if gzip enable. | 21 | // it's used for serve static file if gzip enable. |
| 22 | func OpenMemZipFile(path string, zip string) (*MemFile, error) { | 22 | func openMemZipFile(path string, zip string) (*memFile, error) { |
| 23 | osfile, e := os.Open(path) | 23 | osfile, e := os.Open(path) |
| 24 | if e != nil { | 24 | if e != nil { |
| 25 | return nil, e | 25 | return nil, e |
| ... | @@ -36,12 +36,9 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) { | ... | @@ -36,12 +36,9 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) { |
| 36 | lock.RLock() | 36 | lock.RLock() |
| 37 | cfi, ok := gmfim[zip+":"+path] | 37 | cfi, ok := gmfim[zip+":"+path] |
| 38 | lock.RUnlock() | 38 | lock.RUnlock() |
| 39 | if ok && cfi.ModTime() == modtime && cfi.fileSize == fileSize { | 39 | if !(ok && cfi.ModTime() == modtime && cfi.fileSize == fileSize) { |
| 40 | |||
| 41 | } else { | ||
| 42 | var content []byte | 40 | var content []byte |
| 43 | if zip == "gzip" { | 41 | if zip == "gzip" { |
| 44 | //将文件内容压缩到zipbuf中 | ||
| 45 | var zipbuf bytes.Buffer | 42 | var zipbuf bytes.Buffer |
| 46 | gzipwriter, e := gzip.NewWriterLevel(&zipbuf, gzip.BestCompression) | 43 | gzipwriter, e := gzip.NewWriterLevel(&zipbuf, gzip.BestCompression) |
| 47 | if e != nil { | 44 | if e != nil { |
| ... | @@ -52,13 +49,11 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) { | ... | @@ -52,13 +49,11 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) { |
| 52 | if e != nil { | 49 | if e != nil { |
| 53 | return nil, e | 50 | return nil, e |
| 54 | } | 51 | } |
| 55 | //读zipbuf到content | ||
| 56 | content, e = ioutil.ReadAll(&zipbuf) | 52 | content, e = ioutil.ReadAll(&zipbuf) |
| 57 | if e != nil { | 53 | if e != nil { |
| 58 | return nil, e | 54 | return nil, e |
| 59 | } | 55 | } |
| 60 | } else if zip == "deflate" { | 56 | } else if zip == "deflate" { |
| 61 | //将文件内容压缩到zipbuf中 | ||
| 62 | var zipbuf bytes.Buffer | 57 | var zipbuf bytes.Buffer |
| 63 | deflatewriter, e := flate.NewWriter(&zipbuf, flate.BestCompression) | 58 | deflatewriter, e := flate.NewWriter(&zipbuf, flate.BestCompression) |
| 64 | if e != nil { | 59 | if e != nil { |
| ... | @@ -69,7 +64,6 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) { | ... | @@ -69,7 +64,6 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) { |
| 69 | if e != nil { | 64 | if e != nil { |
| 70 | return nil, e | 65 | return nil, e |
| 71 | } | 66 | } |
| 72 | //将zipbuf读入到content | ||
| 73 | content, e = ioutil.ReadAll(&zipbuf) | 67 | content, e = ioutil.ReadAll(&zipbuf) |
| 74 | if e != nil { | 68 | if e != nil { |
| 75 | return nil, e | 69 | return nil, e |
| ... | @@ -81,17 +75,17 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) { | ... | @@ -81,17 +75,17 @@ func OpenMemZipFile(path string, zip string) (*MemFile, error) { |
| 81 | } | 75 | } |
| 82 | } | 76 | } |
| 83 | 77 | ||
| 84 | cfi = &MemFileInfo{osfileinfo, modtime, content, int64(len(content)), fileSize} | 78 | cfi = &memFileInfo{osfileinfo, modtime, content, int64(len(content)), fileSize} |
| 85 | lock.Lock() | 79 | lock.Lock() |
| 86 | defer lock.Unlock() | 80 | defer lock.Unlock() |
| 87 | gmfim[zip+":"+path] = cfi | 81 | gmfim[zip+":"+path] = cfi |
| 88 | } | 82 | } |
| 89 | return &MemFile{fi: cfi, offset: 0}, nil | 83 | return &memFile{fi: cfi, offset: 0}, nil |
| 90 | } | 84 | } |
| 91 | 85 | ||
| 92 | // MemFileInfo contains a compressed file bytes and file information. | 86 | // MemFileInfo contains a compressed file bytes and file information. |
| 93 | // it implements os.FileInfo interface. | 87 | // it implements os.FileInfo interface. |
| 94 | type MemFileInfo struct { | 88 | type memFileInfo struct { |
| 95 | os.FileInfo | 89 | os.FileInfo |
| 96 | modTime time.Time | 90 | modTime time.Time |
| 97 | content []byte | 91 | content []byte |
| ... | @@ -100,62 +94,62 @@ type MemFileInfo struct { | ... | @@ -100,62 +94,62 @@ type MemFileInfo struct { |
| 100 | } | 94 | } |
| 101 | 95 | ||
| 102 | // Name returns the compressed filename. | 96 | // Name returns the compressed filename. |
| 103 | func (fi *MemFileInfo) Name() string { | 97 | func (fi *memFileInfo) Name() string { |
| 104 | return fi.Name() | 98 | return fi.Name() |
| 105 | } | 99 | } |
| 106 | 100 | ||
| 107 | // Size returns the raw file content size, not compressed size. | 101 | // Size returns the raw file content size, not compressed size. |
| 108 | func (fi *MemFileInfo) Size() int64 { | 102 | func (fi *memFileInfo) Size() int64 { |
| 109 | return fi.contentSize | 103 | return fi.contentSize |
| 110 | } | 104 | } |
| 111 | 105 | ||
| 112 | // Mode returns file mode. | 106 | // Mode returns file mode. |
| 113 | func (fi *MemFileInfo) Mode() os.FileMode { | 107 | func (fi *memFileInfo) Mode() os.FileMode { |
| 114 | return fi.Mode() | 108 | return fi.Mode() |
| 115 | } | 109 | } |
| 116 | 110 | ||
| 117 | // ModTime returns the last modified time of raw file. | 111 | // ModTime returns the last modified time of raw file. |
| 118 | func (fi *MemFileInfo) ModTime() time.Time { | 112 | func (fi *memFileInfo) ModTime() time.Time { |
| 119 | return fi.modTime | 113 | return fi.modTime |
| 120 | } | 114 | } |
| 121 | 115 | ||
| 122 | // IsDir returns the compressing file is a directory or not. | 116 | // IsDir returns the compressing file is a directory or not. |
| 123 | func (fi *MemFileInfo) IsDir() bool { | 117 | func (fi *memFileInfo) IsDir() bool { |
| 124 | return fi.IsDir() | 118 | return fi.IsDir() |
| 125 | } | 119 | } |
| 126 | 120 | ||
| 127 | // return nil. implement the os.FileInfo interface method. | 121 | // return nil. implement the os.FileInfo interface method. |
| 128 | func (fi *MemFileInfo) Sys() interface{} { | 122 | func (fi *memFileInfo) Sys() interface{} { |
| 129 | return nil | 123 | return nil |
| 130 | } | 124 | } |
| 131 | 125 | ||
| 132 | // MemFile contains MemFileInfo and bytes offset when reading. | 126 | // MemFile contains MemFileInfo and bytes offset when reading. |
| 133 | // it implements io.Reader,io.ReadCloser and io.Seeker. | 127 | // it implements io.Reader,io.ReadCloser and io.Seeker. |
| 134 | type MemFile struct { | 128 | type memFile struct { |
| 135 | fi *MemFileInfo | 129 | fi *memFileInfo |
| 136 | offset int64 | 130 | offset int64 |
| 137 | } | 131 | } |
| 138 | 132 | ||
| 139 | // Close memfile. | 133 | // Close memfile. |
| 140 | func (f *MemFile) Close() error { | 134 | func (f *memFile) Close() error { |
| 141 | return nil | 135 | return nil |
| 142 | } | 136 | } |
| 143 | 137 | ||
| 144 | // Get os.FileInfo of memfile. | 138 | // Get os.FileInfo of memfile. |
| 145 | func (f *MemFile) Stat() (os.FileInfo, error) { | 139 | func (f *memFile) Stat() (os.FileInfo, error) { |
| 146 | return f.fi, nil | 140 | return f.fi, nil |
| 147 | } | 141 | } |
| 148 | 142 | ||
| 149 | // read os.FileInfo of files in directory of memfile. | 143 | // read os.FileInfo of files in directory of memfile. |
| 150 | // it returns empty slice. | 144 | // it returns empty slice. |
| 151 | func (f *MemFile) Readdir(count int) ([]os.FileInfo, error) { | 145 | func (f *memFile) Readdir(count int) ([]os.FileInfo, error) { |
| 152 | infos := []os.FileInfo{} | 146 | infos := []os.FileInfo{} |
| 153 | 147 | ||
| 154 | return infos, nil | 148 | return infos, nil |
| 155 | } | 149 | } |
| 156 | 150 | ||
| 157 | // Read bytes from the compressed file bytes. | 151 | // Read bytes from the compressed file bytes. |
| 158 | func (f *MemFile) Read(p []byte) (n int, err error) { | 152 | func (f *memFile) Read(p []byte) (n int, err error) { |
| 159 | if len(f.fi.content)-int(f.offset) >= len(p) { | 153 | if len(f.fi.content)-int(f.offset) >= len(p) { |
| 160 | n = len(p) | 154 | n = len(p) |
| 161 | } else { | 155 | } else { |
| ... | @@ -171,7 +165,7 @@ var errWhence = errors.New("Seek: invalid whence") | ... | @@ -171,7 +165,7 @@ var errWhence = errors.New("Seek: invalid whence") |
| 171 | var errOffset = errors.New("Seek: invalid offset") | 165 | var errOffset = errors.New("Seek: invalid offset") |
| 172 | 166 | ||
| 173 | // Read bytes from the compressed file bytes by seeker. | 167 | // Read bytes from the compressed file bytes by seeker. |
| 174 | func (f *MemFile) Seek(offset int64, whence int) (ret int64, err error) { | 168 | func (f *memFile) Seek(offset int64, whence int) (ret int64, err error) { |
| 175 | switch whence { | 169 | switch whence { |
| 176 | default: | 170 | default: |
| 177 | return 0, errWhence | 171 | return 0, errWhence |
| ... | @@ -191,7 +185,7 @@ func (f *MemFile) Seek(offset int64, whence int) (ret int64, err error) { | ... | @@ -191,7 +185,7 @@ func (f *MemFile) Seek(offset int64, whence int) (ret int64, err error) { |
| 191 | // GetAcceptEncodingZip returns accept encoding format in http header. | 185 | // GetAcceptEncodingZip returns accept encoding format in http header. |
| 192 | // zip is first, then deflate if both accepted. | 186 | // zip is first, then deflate if both accepted. |
| 193 | // If no accepted, return empty string. | 187 | // If no accepted, return empty string. |
| 194 | func GetAcceptEncodingZip(r *http.Request) string { | 188 | func getAcceptEncodingZip(r *http.Request) string { |
| 195 | ss := r.Header.Get("Accept-Encoding") | 189 | ss := r.Header.Get("Accept-Encoding") |
| 196 | ss = strings.ToLower(ss) | 190 | ss = strings.ToLower(ss) |
| 197 | if strings.Contains(ss, "gzip") { | 191 | if strings.Contains(ss, "gzip") { |
| ... | @@ -203,22 +197,3 @@ func GetAcceptEncodingZip(r *http.Request) string { | ... | @@ -203,22 +197,3 @@ func GetAcceptEncodingZip(r *http.Request) string { |
| 203 | } | 197 | } |
| 204 | return "" | 198 | return "" |
| 205 | } | 199 | } |
| 206 | |||
| 207 | // CloseZWriter closes the io.Writer after compressing static file. | ||
| 208 | func CloseZWriter(zwriter io.Writer) { | ||
| 209 | if zwriter == nil { | ||
| 210 | return | ||
| 211 | } | ||
| 212 | |||
| 213 | switch zwriter.(type) { | ||
| 214 | case *gzip.Writer: | ||
| 215 | zwriter.(*gzip.Writer).Close() | ||
| 216 | case *flate.Writer: | ||
| 217 | zwriter.(*flate.Writer).Close() | ||
| 218 | //其他情况不close, 保持和默认(非压缩)行为一致 | ||
| 219 | /* | ||
| 220 | case io.WriteCloser: | ||
| 221 | zwriter.(io.WriteCloser).Close() | ||
| 222 | */ | ||
| 223 | } | ||
| 224 | } | ... | ... |
| ... | @@ -7,8 +7,6 @@ import ( | ... | @@ -7,8 +7,6 @@ import ( |
| 7 | "net" | 7 | "net" |
| 8 | "net/http" | 8 | "net/http" |
| 9 | "net/url" | 9 | "net/url" |
| 10 | "os" | ||
| 11 | "path" | ||
| 12 | "reflect" | 10 | "reflect" |
| 13 | "regexp" | 11 | "regexp" |
| 14 | "runtime" | 12 | "runtime" |
| ... | @@ -33,7 +31,7 @@ const ( | ... | @@ -33,7 +31,7 @@ const ( |
| 33 | 31 | ||
| 34 | var ( | 32 | var ( |
| 35 | // supported http methods. | 33 | // supported http methods. |
| 36 | HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head"} | 34 | HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head", "trace", "connect"} |
| 37 | // these beego.Controller's methods shouldn't reflect to AutoRouter | 35 | // these beego.Controller's methods shouldn't reflect to AutoRouter |
| 38 | exceptMethod = []string{"Init", "Prepare", "Finish", "Render", "RenderString", | 36 | exceptMethod = []string{"Init", "Prepare", "Finish", "Render", "RenderString", |
| 39 | "RenderBytes", "Redirect", "Abort", "StopRun", "UrlFor", "ServeJson", "ServeJsonp", | 37 | "RenderBytes", "Redirect", "Abort", "StopRun", "UrlFor", "ServeJson", "ServeJsonp", |
| ... | @@ -544,86 +542,24 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -544,86 +542,24 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 544 | http.Error(w, "Method Not Allowed", 405) | 542 | http.Error(w, "Method Not Allowed", 405) |
| 545 | goto Admin | 543 | goto Admin |
| 546 | } | 544 | } |
| 547 | 545 | //static file server | |
| 548 | if do_filter(BeforeRouter) { | 546 | if serverStaticRouter(context) { |
| 549 | goto Admin | 547 | goto Admin |
| 550 | } | 548 | } |
| 551 | 549 | ||
| 552 | //static file server | 550 | if context.Input.IsPost() { |
| 553 | for prefix, staticDir := range StaticDir { | 551 | if CopyRequestBody && !context.Input.IsUpload() { |
| 554 | if len(prefix) == 0 { | 552 | context.Input.CopyBody() |
| 555 | continue | ||
| 556 | } | ||
| 557 | if r.URL.Path == "/favicon.ico" { | ||
| 558 | file := path.Join(staticDir, r.URL.Path) | ||
| 559 | if utils.FileExists(file) { | ||
| 560 | http.ServeFile(w, r, file) | ||
| 561 | w.started = true | ||
| 562 | goto Admin | ||
| 563 | } | ||
| 564 | } | ||
| 565 | if strings.HasPrefix(r.URL.Path, prefix) { | ||
| 566 | if len(r.URL.Path) > len(prefix) && r.URL.Path[len(prefix)] != '/' { | ||
| 567 | continue | ||
| 568 | } | ||
| 569 | if r.URL.Path == prefix && prefix[len(prefix)-1] != '/' { | ||
| 570 | http.Redirect(rw, r, r.URL.Path+"/", 302) | ||
| 571 | goto Admin | ||
| 572 | } | ||
| 573 | file := path.Join(staticDir, r.URL.Path[len(prefix):]) | ||
| 574 | finfo, err := os.Stat(file) | ||
| 575 | if err != nil { | ||
| 576 | if RunMode == "dev" { | ||
| 577 | Warn(err) | ||
| 578 | } | ||
| 579 | http.NotFound(w, r) | ||
| 580 | goto Admin | ||
| 581 | } | ||
| 582 | //if the request is dir and DirectoryIndex is false then | ||
| 583 | if finfo.IsDir() && !DirectoryIndex { | ||
| 584 | middleware.Exception("403", rw, r, "403 Forbidden") | ||
| 585 | goto Admin | ||
| 586 | } | ||
| 587 | |||
| 588 | //This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request | ||
| 589 | isStaticFileToCompress := false | ||
| 590 | if StaticExtensionsToGzip != nil && len(StaticExtensionsToGzip) > 0 { | ||
| 591 | for _, statExtension := range StaticExtensionsToGzip { | ||
| 592 | if strings.HasSuffix(strings.ToLower(file), strings.ToLower(statExtension)) { | ||
| 593 | isStaticFileToCompress = true | ||
| 594 | break | ||
| 595 | } | ||
| 596 | } | ||
| 597 | } | ||
| 598 | |||
| 599 | if isStaticFileToCompress { | ||
| 600 | if EnableGzip { | ||
| 601 | w.contentEncoding = GetAcceptEncodingZip(r) | ||
| 602 | } | ||
| 603 | |||
| 604 | memzipfile, err := OpenMemZipFile(file, w.contentEncoding) | ||
| 605 | if err != nil { | ||
| 606 | return | ||
| 607 | } | ||
| 608 | |||
| 609 | w.InitHeadContent(finfo.Size()) | ||
| 610 | |||
| 611 | http.ServeContent(w, r, file, finfo.ModTime(), memzipfile) | ||
| 612 | } else { | ||
| 613 | http.ServeFile(w, r, file) | ||
| 614 | } | ||
| 615 | |||
| 616 | w.started = true | ||
| 617 | goto Admin | ||
| 618 | } | 553 | } |
| 554 | context.Input.ParseFormOrMulitForm(MaxMemory) | ||
| 619 | } | 555 | } |
| 620 | 556 | ||
| 621 | if do_filter(AfterStatic) { | 557 | if do_filter(BeforeRouter) { |
| 622 | goto Admin | 558 | goto Admin |
| 623 | } | 559 | } |
| 624 | 560 | ||
| 625 | if CopyRequestBody { | 561 | if do_filter(AfterStatic) { |
| 626 | context.Input.Body() | 562 | goto Admin |
| 627 | } | 563 | } |
| 628 | 564 | ||
| 629 | if context.Input.RunController != nil && context.Input.RunMethod != "" { | 565 | if context.Input.RunController != nil && context.Input.RunMethod != "" { |
| ... | @@ -757,9 +693,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -757,9 +693,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 757 | } | 693 | } |
| 758 | 694 | ||
| 759 | if findrouter { | 695 | if findrouter { |
| 760 | if r.Method == "POST" { | ||
| 761 | r.ParseMultipartForm(MaxMemory) | ||
| 762 | } | ||
| 763 | //execute middleware filters | 696 | //execute middleware filters |
| 764 | if do_filter(BeforeExec) { | 697 | if do_filter(BeforeExec) { |
| 765 | goto Admin | 698 | goto Admin |
| ... | @@ -830,9 +763,8 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -830,9 +763,8 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 830 | } | 763 | } |
| 831 | } | 764 | } |
| 832 | 765 | ||
| 833 | Admin: | ||
| 834 | do_filter(FinishRouter) | 766 | do_filter(FinishRouter) |
| 835 | 767 | Admin: | |
| 836 | //admin module record QPS | 768 | //admin module record QPS |
| 837 | if EnableAdmin { | 769 | if EnableAdmin { |
| 838 | timeend := time.Since(starttime) | 770 | timeend := time.Since(starttime) |
| ... | @@ -891,10 +823,9 @@ func (p *ControllerRegistor) getRunMethod(method string, context *beecontext.Con | ... | @@ -891,10 +823,9 @@ func (p *ControllerRegistor) getRunMethod(method string, context *beecontext.Con |
| 891 | //responseWriter is a wrapper for the http.ResponseWriter | 823 | //responseWriter is a wrapper for the http.ResponseWriter |
| 892 | //started set to true if response was written to then don't execute other handler | 824 | //started set to true if response was written to then don't execute other handler |
| 893 | type responseWriter struct { | 825 | type responseWriter struct { |
| 894 | writer http.ResponseWriter | 826 | writer http.ResponseWriter |
| 895 | started bool | 827 | started bool |
| 896 | status int | 828 | status int |
| 897 | contentEncoding string | ||
| 898 | } | 829 | } |
| 899 | 830 | ||
| 900 | // Header returns the header map that will be sent by WriteHeader. | 831 | // Header returns the header map that will be sent by WriteHeader. |
| ... | @@ -902,17 +833,6 @@ func (w *responseWriter) Header() http.Header { | ... | @@ -902,17 +833,6 @@ func (w *responseWriter) Header() http.Header { |
| 902 | return w.writer.Header() | 833 | return w.writer.Header() |
| 903 | } | 834 | } |
| 904 | 835 | ||
| 905 | // Init content-length header. | ||
| 906 | func (w *responseWriter) InitHeadContent(contentlength int64) { | ||
| 907 | if w.contentEncoding == "gzip" { | ||
| 908 | w.Header().Set("Content-Encoding", "gzip") | ||
| 909 | } else if w.contentEncoding == "deflate" { | ||
| 910 | w.Header().Set("Content-Encoding", "deflate") | ||
| 911 | } else { | ||
| 912 | w.Header().Set("Content-Length", strconv.FormatInt(contentlength, 10)) | ||
| 913 | } | ||
| 914 | } | ||
| 915 | |||
| 916 | // Write writes the data to the connection as part of an HTTP reply, | 836 | // Write writes the data to the connection as part of an HTTP reply, |
| 917 | // and sets `started` to true. | 837 | // and sets `started` to true. |
| 918 | // started means the response has sent out. | 838 | // started means the response has sent out. | ... | ... |
staticfile.go
0 → 100644
| 1 | package beego | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "net/http" | ||
| 5 | "os" | ||
| 6 | "path" | ||
| 7 | "strconv" | ||
| 8 | "strings" | ||
| 9 | |||
| 10 | "github.com/astaxie/beego/context" | ||
| 11 | "github.com/astaxie/beego/middleware" | ||
| 12 | "github.com/astaxie/beego/utils" | ||
| 13 | ) | ||
| 14 | |||
| 15 | func serverStaticRouter(ctx *context.Context) bool { | ||
| 16 | requestPath := ctx.Input.Request.URL.Path | ||
| 17 | for prefix, staticDir := range StaticDir { | ||
| 18 | if len(prefix) == 0 { | ||
| 19 | continue | ||
| 20 | } | ||
| 21 | if requestPath == "/favicon.ico" { | ||
| 22 | file := path.Join(staticDir, requestPath) | ||
| 23 | if utils.FileExists(file) { | ||
| 24 | http.ServeFile(ctx.ResponseWriter, ctx.Request, file) | ||
| 25 | return true | ||
| 26 | } | ||
| 27 | } | ||
| 28 | if strings.HasPrefix(requestPath, prefix) { | ||
| 29 | if len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' { | ||
| 30 | continue | ||
| 31 | } | ||
| 32 | if requestPath == prefix && prefix[len(prefix)-1] != '/' { | ||
| 33 | http.Redirect(ctx.ResponseWriter, ctx.Request, requestPath+"/", 302) | ||
| 34 | return true | ||
| 35 | } | ||
| 36 | file := path.Join(staticDir, requestPath[len(prefix):]) | ||
| 37 | finfo, err := os.Stat(file) | ||
| 38 | if err != nil { | ||
| 39 | if RunMode == "dev" { | ||
| 40 | Warn(err) | ||
| 41 | } | ||
| 42 | http.NotFound(ctx.ResponseWriter, ctx.Request) | ||
| 43 | return true | ||
| 44 | } | ||
| 45 | //if the request is dir and DirectoryIndex is false then | ||
| 46 | if finfo.IsDir() && !DirectoryIndex { | ||
| 47 | middleware.Exception("403", ctx.ResponseWriter, ctx.Request, "403 Forbidden") | ||
| 48 | return true | ||
| 49 | } | ||
| 50 | |||
| 51 | //This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request | ||
| 52 | isStaticFileToCompress := false | ||
| 53 | if StaticExtensionsToGzip != nil && len(StaticExtensionsToGzip) > 0 { | ||
| 54 | for _, statExtension := range StaticExtensionsToGzip { | ||
| 55 | if strings.HasSuffix(strings.ToLower(file), strings.ToLower(statExtension)) { | ||
| 56 | isStaticFileToCompress = true | ||
| 57 | break | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | if isStaticFileToCompress { | ||
| 63 | var contentEncoding string | ||
| 64 | if EnableGzip { | ||
| 65 | contentEncoding = getAcceptEncodingZip(ctx.Request) | ||
| 66 | } | ||
| 67 | |||
| 68 | memzipfile, err := openMemZipFile(file, contentEncoding) | ||
| 69 | if err != nil { | ||
| 70 | return true | ||
| 71 | } | ||
| 72 | |||
| 73 | if contentEncoding == "gzip" { | ||
| 74 | ctx.Output.Header("Content-Encoding", "gzip") | ||
| 75 | } else if contentEncoding == "deflate" { | ||
| 76 | ctx.Output.Header("Content-Encoding", "deflate") | ||
| 77 | } else { | ||
| 78 | ctx.Output.Header("Content-Length", strconv.FormatInt(finfo.Size(), 10)) | ||
| 79 | } | ||
| 80 | |||
| 81 | http.ServeContent(ctx.ResponseWriter, ctx.Request, file, finfo.ModTime(), memzipfile) | ||
| 82 | |||
| 83 | } else { | ||
| 84 | http.ServeFile(ctx.ResponseWriter, ctx.Request, file) | ||
| 85 | } | ||
| 86 | return true | ||
| 87 | } | ||
| 88 | } | ||
| 89 | return false | ||
| 90 | } |
-
Please register or sign in to post a comment