From f5660fbc48956b182f44408f62fce5dbb4e164ea Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Mon, 31 Oct 2016 21:25:14 +0000 Subject: [PATCH] general improvements; updates on #32 --- README.md | 1 + config/config.go | 4 +- handlers/command.go | 180 ++++++++++++++++---------------------------- handlers/editor.go | 5 +- page/page.go | 2 +- 5 files changed, 74 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 2656eeec..a8063d29 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![Build](https://img.shields.io/travis/hacdias/caddy-filemanager.svg?style=flat-square)](https://travis-ci.org/hacdias/caddy-filemanager) [![community](https://img.shields.io/badge/community-forum-ff69b4.svg?style=flat-square)](https://forum.caddyserver.com) [![Documentation](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/hacdias/caddy-filemanager) +[![Go Report Card](https://goreportcard.com/badge/github.com/hacdias/caddy-filemanager?style=flat-square)](https://goreportcard.com/report/hacdias/caddy-filemanager This package is a plugin for Caddy server that provides an online file manager (based on browse middleware) that is able to: rename files, delete files and upload files. Some new features that can be implemented in the future can be seen at [issues](https://github.com/hacdias/caddy-filemanager/issues). diff --git a/config/config.go b/config/config.go index cf008598..5d6d9817 100644 --- a/config/config.go +++ b/config/config.go @@ -13,7 +13,7 @@ import ( "github.com/mholt/caddy/caddyhttp/httpserver" ) -// Config is a configuration for browsing in a particualr path. +// Config is a configuration for browsing in a particular path. type Config struct { *User BaseURL string @@ -66,7 +66,7 @@ func Parse(c *caddy.Controller) ([]Config, error) { cfg.AllowEdit = true cfg.AllowNew = true cfg.Commands = []string{"git", "svn", "hg"} - cfg.Rules = []*Rule{&Rule{ + cfg.Rules = []*Rule{{ Regex: true, Allow: false, Regexp: regexp.MustCompile("\\/\\..+"), diff --git a/handlers/command.go b/handlers/command.go index b1266aa1..0b2ee12e 100644 --- a/handlers/command.go +++ b/handlers/command.go @@ -2,7 +2,6 @@ package handlers import ( "bytes" - "fmt" "net/http" "os/exec" "path/filepath" @@ -18,167 +17,120 @@ var upgrader = websocket.Upgrader{ WriteBufferSize: 1024, } +var ( + cmdNotImplemented = []byte("Command not implemented.") + cmdNotAllowed = []byte("Command not allowed.") +) + // Command handles the requests for VCS related commands: git, svn and mercurial func Command(w http.ResponseWriter, r *http.Request, c *config.Config, u *config.User) (int, error) { + // Upgrades the connection to a websocket and checks for errors. conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - fmt.Println(err) - return 0, nil + return 0, err } defer conn.Close() + var ( + message []byte + command []string + ) + + // Starts an infinite loop until a valid command is captured. for { - _, message, err := conn.ReadMessage() - if err != nil { - fmt.Println("read:", err) - break - } - - command := strings.Split(string(message), " ") - - if len(command) == 0 { - continue - } - // Check if the command is allowed - mayContinue := false - - for _, cmd := range u.Commands { - if cmd == command[0] { - mayContinue = true - } - } - - if !mayContinue { - err = conn.WriteMessage(websocket.BinaryMessage, []byte("FORBIDDEN")) - if err != nil { - fmt.Println("write:", err) - break - } - - return 0, nil - } - - // Check if the program is talled is installed on the computer - if _, err = exec.LookPath(command[0]); err != nil { - err = conn.WriteMessage(websocket.BinaryMessage, []byte("Command not implemented.")) - if err != nil { - fmt.Println("write:", err) - break - } - - return http.StatusNotImplemented, nil - } - - path := strings.Replace(r.URL.Path, c.BaseURL, c.Scope, 1) - path = filepath.Clean(path) - - buff := new(bytes.Buffer) - - cmd := exec.Command(command[0], command[1:len(command)]...) - cmd.Dir = path - cmd.Stderr = buff - cmd.Stdout = buff - err = cmd.Start() + _, message, err = conn.ReadMessage() if err != nil { return http.StatusInternalServerError, err } - done := false - go func() { - err = cmd.Wait() - done = true - }() - - for !done { - by := buff.Bytes() - if len(by) > 0 { - err = conn.WriteMessage(websocket.TextMessage, by) - if err != nil { - fmt.Println("write:", err) - break - } - } - - time.Sleep(100 * time.Millisecond) + command = strings.Split(string(message), " ") + if len(command) != 0 { + break } - - by := buff.Bytes() - if len(by) > 0 { - err = conn.WriteMessage(websocket.TextMessage, by) - if err != nil { - fmt.Println("write:", err) - break - } - } - - time.Sleep(100 * time.Millisecond) - - break } - /* command := strings.Split(r.Header.Get("command"), " ") - // Check if the command is allowed - mayContinue := false + allowed := false for _, cmd := range u.Commands { if cmd == command[0] { - mayContinue = true + allowed = true } } - if !mayContinue { - return http.StatusForbidden, nil + if !allowed { + err = conn.WriteMessage(websocket.BinaryMessage, cmdNotAllowed) + if err != nil { + return http.StatusInternalServerError, err + } + + return 0, nil } - // Check if the program is talled is installed on the computer - if _, err := exec.LookPath(command[0]); err != nil { + // Check if the program is talled is installed on the computer. + if _, err = exec.LookPath(command[0]); err != nil { + err = conn.WriteMessage(websocket.BinaryMessage, cmdNotImplemented) + if err != nil { + return http.StatusInternalServerError, err + } + return http.StatusNotImplemented, nil } + // Gets the path and initializes a buffer. path := strings.Replace(r.URL.Path, c.BaseURL, c.Scope, 1) path = filepath.Clean(path) + buff := new(bytes.Buffer) - cmd := exec.Command(command[0], command[1:len(command)]...) + // Sets up the command executation. + cmd := exec.Command(command[0], command[1:]...) cmd.Dir = path - cmd.Stderr = w - cmd.Stdout = w - cmd.Start() + cmd.Stderr = buff + cmd.Stdout = buff - /*cmd.Stderr = b - cmd.Stdout = b - - // Starts the comamnd - err := cmd.Start() + // Starts the command and checks for errors. + err = cmd.Start() if err != nil { return http.StatusInternalServerError, err } + // Set a 'done' variable to check whetever the command has already finished + // running or not. This verification is done using a goroutine that uses the + // method .Wait() from the command. done := false go func() { err = cmd.Wait() done = true }() - for !done { - by := b.Bytes() + // Function to print the current information on the buffer to the connection. + print := func() error { + by := buff.Bytes() if len(by) > 0 { - fmt.Println(string(by)) + err = conn.WriteMessage(websocket.TextMessage, by) + if err != nil { + return err + } } - //w.Write(by) + return nil + } - }*/ + // While the command hasn't finished running, continue sending the output + // to the client in intervals of 100 milliseconds. + for !done { + if err = print(); err != nil { + return http.StatusInternalServerError, err + } - //out, err := cmd.CombinedOutput() - //fmt.Println(string(out)) + time.Sleep(100 * time.Millisecond) + } - //if err != nil { - // return http.StatusInternalServerError, err - //} + // After the command is done executing, send the output one more time to the + // browser to make sure it gets the latest information. + if err = print(); err != nil { + return http.StatusInternalServerError, err + } - /* cmd.Wait() - - //p := &page.Page{Info: &page.Info{Data: string(output)}} */ return 0, nil } diff --git a/handlers/editor.go b/handlers/editor.go index f9343538..ee26bd69 100644 --- a/handlers/editor.go +++ b/handlers/editor.go @@ -70,7 +70,10 @@ func GetEditor(i *file.Info) (*Editor, error) { // Parses the page content and the frontmatter editor.Content = strings.TrimSpace(string(page.Content())) editor.FrontMatter, _, err = frontmatter.Pretty(page.FrontMatter()) - break + + if err == nil { + break + } } } diff --git a/page/page.go b/page/page.go index dd7c60a3..8ed97b3d 100644 --- a/page/page.go +++ b/page/page.go @@ -133,7 +133,7 @@ func (p Page) PrintAsHTML(w http.ResponseWriter, templates ...string) (int, erro w.Header().Set("Content-Type", "text/html; charset=utf-8") _, err = buf.WriteTo(w) - return http.StatusOK, nil + return http.StatusOK, err } // PrintAsJSON prints the current Page infromation in JSON