From fec7fa8bfda713e8042b9bbf9a480c7792b78c41 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Mon, 20 May 2019 10:59:20 -0600 Subject: Implement most of static file server; refactor and improve Replacer --- modules/caddyhttp/staticfiles/browse.go | 205 ++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 modules/caddyhttp/staticfiles/browse.go (limited to 'modules/caddyhttp/staticfiles/browse.go') diff --git a/modules/caddyhttp/staticfiles/browse.go b/modules/caddyhttp/staticfiles/browse.go new file mode 100644 index 0000000..15ff105 --- /dev/null +++ b/modules/caddyhttp/staticfiles/browse.go @@ -0,0 +1,205 @@ +package staticfiles + +import ( + "net/http" +) + +// Browse configures directory browsing. +type Browse struct { +} + +// ServeHTTP determines if the request is for this plugin, and if all prerequisites are met. +// If so, control is handed over to ServeListing. +func (b Browse) ServeHTTP(w http.ResponseWriter, r *http.Request) error { + // TODO: convert this handler + return nil + + // // Browse works on existing directories; delegate everything else + // requestedFilepath, err := bc.Fs.Root.Open(r.URL.Path) + // if err != nil { + // switch { + // case os.IsPermission(err): + // return http.StatusForbidden, err + // case os.IsExist(err): + // return http.StatusNotFound, err + // default: + // return b.Next.ServeHTTP(w, r) + // } + // } + // defer requestedFilepath.Close() + + // info, err := requestedFilepath.Stat() + // if err != nil { + // switch { + // case os.IsPermission(err): + // return http.StatusForbidden, err + // case os.IsExist(err): + // return http.StatusGone, err + // default: + // return b.Next.ServeHTTP(w, r) + // } + // } + // if !info.IsDir() { + // return b.Next.ServeHTTP(w, r) + // } + + // // Do not reply to anything else because it might be nonsensical + // switch r.Method { + // case http.MethodGet, http.MethodHead: + // // proceed, noop + // case "PROPFIND", http.MethodOptions: + // return http.StatusNotImplemented, nil + // default: + // return b.Next.ServeHTTP(w, r) + // } + + // // Browsing navigation gets messed up if browsing a directory + // // that doesn't end in "/" (which it should, anyway) + // u := *r.URL + // if u.Path == "" { + // u.Path = "/" + // } + // if u.Path[len(u.Path)-1] != '/' { + // u.Path += "/" + // http.Redirect(w, r, u.String(), http.StatusMovedPermanently) + // return http.StatusMovedPermanently, nil + // } + + // return b.ServeListing(w, r, requestedFilepath, bc) +} + +// func (b Browse) loadDirectoryContents(requestedFilepath http.File, urlPath string, config *Config) (*Listing, bool, error) { +// files, err := requestedFilepath.Readdir(-1) +// if err != nil { +// return nil, false, err +// } + +// // Determine if user can browse up another folder +// var canGoUp bool +// curPathDir := path.Dir(strings.TrimSuffix(urlPath, "/")) +// for _, other := range b.Configs { +// if strings.HasPrefix(curPathDir, other.PathScope) { +// canGoUp = true +// break +// } +// } + +// // Assemble listing of directory contents +// listing, hasIndex := directoryListing(files, canGoUp, urlPath, config) + +// return &listing, hasIndex, nil +// } + +// // handleSortOrder gets and stores for a Listing the 'sort' and 'order', +// // and reads 'limit' if given. The latter is 0 if not given. +// // +// // This sets Cookies. +// func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (sort string, order string, limit int, err error) { +// sort, order, limitQuery := r.URL.Query().Get("sort"), r.URL.Query().Get("order"), r.URL.Query().Get("limit") + +// // If the query 'sort' or 'order' is empty, use defaults or any values previously saved in Cookies +// switch sort { +// case "": +// sort = sortByNameDirFirst +// if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil { +// sort = sortCookie.Value +// } +// case sortByName, sortByNameDirFirst, sortBySize, sortByTime: +// http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil}) +// } + +// switch order { +// case "": +// order = "asc" +// if orderCookie, orderErr := r.Cookie("order"); orderErr == nil { +// order = orderCookie.Value +// } +// case "asc", "desc": +// http.SetCookie(w, &http.Cookie{Name: "order", Value: order, Path: scope, Secure: r.TLS != nil}) +// } + +// if limitQuery != "" { +// limit, err = strconv.Atoi(limitQuery) +// if err != nil { // if the 'limit' query can't be interpreted as a number, return err +// return +// } +// } + +// return +// } + +// // ServeListing returns a formatted view of 'requestedFilepath' contents'. +// func (b Browse) ServeListing(w http.ResponseWriter, r *http.Request, requestedFilepath http.File, bc *Config) (int, error) { +// listing, containsIndex, err := b.loadDirectoryContents(requestedFilepath, r.URL.Path, bc) +// if err != nil { +// switch { +// case os.IsPermission(err): +// return http.StatusForbidden, err +// case os.IsExist(err): +// return http.StatusGone, err +// default: +// return http.StatusInternalServerError, err +// } +// } +// if containsIndex && !b.IgnoreIndexes { // directory isn't browsable +// return b.Next.ServeHTTP(w, r) +// } +// listing.Context = httpserver.Context{ +// Root: bc.Fs.Root, +// Req: r, +// URL: r.URL, +// } +// listing.User = bc.Variables + +// // Copy the query values into the Listing struct +// var limit int +// listing.Sort, listing.Order, limit, err = b.handleSortOrder(w, r, bc.PathScope) +// if err != nil { +// return http.StatusBadRequest, err +// } + +// listing.applySort() + +// if limit > 0 && limit <= len(listing.Items) { +// listing.Items = listing.Items[:limit] +// listing.ItemsLimitedTo = limit +// } + +// var buf *bytes.Buffer +// acceptHeader := strings.ToLower(strings.Join(r.Header["Accept"], ",")) +// switch { +// case strings.Contains(acceptHeader, "application/json"): +// if buf, err = b.formatAsJSON(listing, bc); err != nil { +// return http.StatusInternalServerError, err +// } +// w.Header().Set("Content-Type", "application/json; charset=utf-8") + +// default: // There's no 'application/json' in the 'Accept' header; browse normally +// if buf, err = b.formatAsHTML(listing, bc); err != nil { +// return http.StatusInternalServerError, err +// } +// w.Header().Set("Content-Type", "text/html; charset=utf-8") + +// } + +// _, _ = buf.WriteTo(w) + +// return http.StatusOK, nil +// } + +// func (b Browse) formatAsJSON(listing *Listing, bc *Config) (*bytes.Buffer, error) { +// marsh, err := json.Marshal(listing.Items) +// if err != nil { +// return nil, err +// } + +// buf := new(bytes.Buffer) +// _, err = buf.Write(marsh) +// return buf, err +// } + +// func (b Browse) formatAsHTML(listing *Listing, bc *Config) (*bytes.Buffer, error) { +// buf := new(bytes.Buffer) +// err := bc.Template.Execute(buf, listing) +// return buf, err +// } -- cgit v1.2.3