diff --git a/README.md b/README.md index fbfe788f..fa944c94 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,13 @@ [![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) + +This is just a concept of syntax: + +``` +filemanager { + show path + on url + styles filepath +} +``` diff --git a/assets/assets.go b/assets/assets.go index d376e4f9..a31823d6 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -7,35 +7,20 @@ package assets import ( - "bytes" - "compress/gzip" "fmt" - "io" "io/ioutil" "os" "path/filepath" "strings" - "time" ) -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) +// bindataRead reads the given file from disk. It returns an error on failure. +func bindataRead(path, name string) ([]byte, error) { + buf, err := ioutil.ReadFile(path) if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) + err = fmt.Errorf("Error reading asset %s at %s: %v", name, path, err) } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("Read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil + return buf, err } type asset struct { @@ -43,70 +28,40 @@ type asset struct { info os.FileInfo } -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -func (fi bindataFileInfo) Name() string { - return fi.name -} -func (fi bindataFileInfo) Size() int64 { - return fi.size -} -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} -func (fi bindataFileInfo) IsDir() bool { - return false -} -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _stylesCss = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x55\xdd\x4e\xe3\x3c\x10\xbd\x6e\xa5\xbe\x83\x25\x84\x04\x9f\x48\x95\x14\xca\x27\xd2\x9b\x95\xf6\x1d\xf6\x7e\x12\x4f\x1a\x0b\xc7\x8e\x6c\x97\x96\x45\xfb\xee\x3b\x76\xea\xc6\xa1\x61\x57\x4b\x90\x48\xe6\xcf\x33\xe7\x1c\x0f\xff\xb1\x0f\xd6\x03\xe7\x42\xed\x4b\x96\xef\x58\x07\x66\x2f\x54\x78\xfd\xb5\x5a\xae\x96\x95\xe6\xef\xec\x63\xb5\x5c\x34\x5a\xb9\xac\x81\x4e\xc8\xf7\x92\x59\x50\x36\xb3\x68\x44\xb3\x23\x97\xc3\x93\xcb\x0c\x2a\x4e\x06\x5f\x46\xf7\x4e\x74\xe2\x27\xda\x1e\x91\x53\x40\x28\x04\xa1\x4a\xad\xa5\x36\x25\xbb\xc9\xf3\x67\xe4\x8f\x97\x64\x8e\xb5\x36\xe0\x84\xa6\x93\x95\x56\x78\x49\x2a\x5b\xfd\x86\xe6\x61\xb5\x6c\x0b\x76\xfe\x98\xd4\x79\x2c\x5e\xea\xa6\x89\xe1\x2d\x02\x0f\xd1\x37\xf6\xd0\xd1\x24\x43\xe7\xe7\xf1\x32\x89\x8d\x2b\xd9\xf6\x76\x97\xd8\x8c\xd8\xb7\xd1\x18\x4a\xb8\xb6\x6c\x84\xb1\x2e\xab\x5b\x21\x39\x95\x72\x3c\x35\x7c\x55\x30\xe6\x4a\x98\xa6\x8e\xdf\x93\xcc\xab\x63\x87\xce\x27\x31\x4e\xf7\x25\xdb\x6c\xfb\x53\xda\x6f\xa5\x9d\xd3\x5d\xc9\x8a\xb3\xbd\x82\xfa\x75\x6f\xf4\x41\xf1\x2c\x42\xd2\x6c\xfc\x73\x29\x5c\x8c\xec\x59\xe2\x84\x4a\xe6\x43\x6a\x30\x1d\x71\xe8\x44\x69\xd3\x81\xf4\xe6\x63\x2b\x1c\x66\xb6\x87\x1a\xbd\xf9\x68\xa0\xf7\x66\x8f\x7c\x23\xf5\x31\x3b\x95\xac\x15\x9c\xa3\xba\x90\x17\x5d\x25\x43\x29\x45\x6f\x85\x4d\x0e\x9f\xd0\x2e\x54\x4b\x12\x71\xa9\x3b\xe1\xf4\x4a\x09\x07\xaf\x28\x29\x46\x39\x74\x20\x54\x08\xe5\xc2\xf6\x12\x48\x88\x95\xd4\xf5\x6b\x74\xaf\x3b\x74\xf0\x79\xdc\x62\x93\x8c\x1b\xf5\xfb\x03\x0d\x07\x05\x0f\x9f\x84\x5c\x69\x43\x27\x8e\x20\xf7\x27\x66\xb5\x14\x9c\xdd\xbc\x7c\xf7\xcf\xee\x33\x3d\xc5\x9f\xe9\x19\xbb\xca\x08\xd4\x2e\xb4\x36\x5c\xb0\xa8\x80\x02\xbb\x8b\x7a\xa0\x92\x18\x42\x8e\x82\x93\x94\x58\x91\xe7\xb7\x49\x57\x84\xa1\x84\xde\xd2\x48\xf1\xed\x92\x39\xe0\x37\xd3\x3d\x07\xdb\x22\xb5\xcf\xc1\x3f\x63\x7c\xa9\xb4\xbb\x4b\x75\x7d\x9f\xf0\x30\xa7\x29\xfa\xc1\x7a\xd4\x79\x10\xf7\x48\x1a\x48\xb1\x27\xbe\xfc\x7d\x48\xd0\xf0\x13\x50\x0f\xf9\x98\x76\xad\xef\xbf\x00\x38\x21\xf2\x79\x30\xcd\x0b\x34\x9e\x30\xd1\x5b\x25\x61\x54\x07\x39\xed\xdb\x3e\xb8\x69\x52\x27\x6a\x90\xb1\xf1\x8e\x04\x2d\x47\x38\xf9\x95\x86\x9e\x46\x3a\x67\xf6\xc1\x99\xaf\x6d\xfe\x0f\x9b\x20\xc5\x2d\x68\xe1\x8b\xfa\xb1\xe5\x5e\x5b\x31\xdc\x0a\xa8\x48\x93\x07\x97\xb6\xbb\x56\xd0\xe1\xc0\xc9\x7a\xaf\x0f\x7d\x2a\xb4\x61\x49\x15\xeb\xff\xb7\x41\x6a\x8b\x23\xa9\x24\xab\x0c\xc2\x2b\xe1\xe3\xff\x50\x17\x72\x72\xc3\x3d\xa2\xd1\xe7\xa3\xaf\x40\xef\x0d\x66\x29\xec\x8d\xd6\x6e\xba\xbc\x4a\xf6\xe4\xa9\x9f\xac\x9a\xe9\x75\x4c\xe7\xaf\x51\x51\x7e\xac\xf6\xad\x43\x2e\x80\xdd\x75\x70\xca\xce\xc8\x3e\xe7\x54\xe8\x3e\x1c\xb0\xa6\xe5\x83\x97\x9b\x32\x2e\x82\xf3\x7f\x8d\x45\x28\xb1\x98\x21\x29\xb2\x04\x07\xa7\x93\xc0\xb6\x54\xae\x1d\xc2\xee\x36\xf7\x0f\x43\x6e\x6a\x1a\x92\xe7\x16\xf7\x62\x96\x44\x5f\x98\x7e\x7f\x07\x00\x00\xff\xff\x8c\x4d\x45\x42\x58\x07\x00\x00") - -func stylesCssBytes() ([]byte, error) { - return bindataRead( - _stylesCss, - "styles.css", - ) -} - +// stylesCss reads file data from disk. It returns an error on failure. func stylesCss() (*asset, error) { - bytes, err := stylesCssBytes() + path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-filemanager\\assets\\source\\styles.css" + name := "styles.css" + bytes, err := bindataRead(path, name) if err != nil { return nil, err } - info := bindataFileInfo{name: "styles.css", size: 1880, mode: os.FileMode(438), modTime: time.Unix(1465578069, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _templateTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xec\x5a\xdd\x6f\xe3\xb8\x11\x7f\x4e\x81\xfe\x0f\x3c\xdd\xe1\xce\x06\x56\x94\x48\x7d\x67\xe5\x14\x77\xbb\xd7\xed\x01\xfb\x71\xe8\x66\x1f\xda\x97\x03\x2d\xd1\xb6\x7a\xb2\xe4\x52\xb2\x13\x6f\x90\xff\xbd\x33\xa2\x64\xcb\x8e\x92\x38\xdd\xbd\xc5\x16\x28\x1c\x44\xa4\x34\x1c\xce\xfc\xe6\x8b\xa4\x14\x7f\xf3\xf2\xdd\x8b\xcb\x7f\xfc\xfa\x33\x59\xd4\xcb\xfc\xe2\xcf\x7f\x8a\xdb\xeb\x59\xbc\x90\x22\xc5\xc6\x59\x5c\x67\x75\x2e\x2f\x6e\x6e\xe8\x5b\xb1\x94\xb7\xb7\xb1\xa5\x6f\x34\xcf\x96\xb2\x16\xa4\x80\xfb\x13\x63\x93\xc9\xab\x55\xa9\x6a\x83\x24\x65\x51\xcb\xa2\x9e\x18\x57\x59\x5a\x2f\x26\xa9\xdc\x64\x89\x34\x9b\xce\x33\x92\x15\x59\x9d\x89\xdc\xac\x12\x91\xcb\x09\xa3\xb6\x01\x9c\x90\x17\x21\x71\x9e\x15\xbf\x13\x25\xf3\x89\x51\xd5\xdb\x5c\x56\x0b\x29\x81\xdd\x42\xc9\xd9\xc4\xb0\x7e\x9b\x65\xb9\x5c\x8a\x42\xcc\xa5\xfa\x2d\x83\x19\x54\x21\x72\x4b\x13\xd2\xa4\xaa\x90\x4f\xdc\x74\x1b\x86\xb1\xd5\xb5\xcf\x62\xab\x53\x26\x9e\x96\xe9\x56\x4b\x5e\x6d\xe6\x64\x23\x55\x95\x95\xc5\xc4\x60\x94\x19\xe4\x7a\x99\x17\xd5\xc4\x58\xd4\xf5\xea\xdc\xb2\xae\xae\xae\xe8\x95\x43\x4b\x35\xb7\xb8\x6d\xdb\x16\xd0\xb7\x24\xe7\xd7\x28\xe7\x10\x21\x8b\xa2\xc8\x6a\x9e\x82\xd4\x32\x9b\x2f\x00\x03\xdb\x20\x1a\x06\x6c\x35\x22\x4d\x8c\x55\x59\x01\x08\x65\x71\x4e\xc4\xb4\x2a\xf3\x75\x2d\x9f\x1b\x8d\x54\x67\x71\x2a\x67\x95\x6e\x9e\xc5\xdf\x98\x26\xf9\x6b\x99\xa7\x52\x11\xd3\xec\x6e\x02\x77\x29\xd4\x2b\x25\xd2\x0c\x30\x26\x59\x3a\x31\x66\x06\xd9\xf2\x89\xe1\xbb\x30\xc3\xbc\x7d\xf0\x01\x60\x06\x65\xd6\x95\x54\xef\x57\x22\x91\xef\x8a\x0f\x95\x04\x05\x80\x8e\xbb\x2e\x0d\xdd\x3d\xe9\xa5\x12\x45\x35\x2b\xd5\x72\x62\x2c\x45\xad\xb2\xeb\x11\x8d\x02\x87\x45\xc4\x86\x1f\x18\x88\x39\x1e\x31\xa9\x67\xfb\x11\x5c\x99\x43\xfd\x20\x1a\xc3\x8c\x6c\x62\xb8\xcc\xa3\x81\x07\x5c\xd9\x8e\x6b\x2b\x26\xe0\x5b\x97\x2b\x82\xff\xcc\xa4\xcc\x4b\x35\x31\xbe\x9d\x3a\x69\x3a\x4b\x0d\x52\xce\x66\x95\x6c\x90\xb1\x1e\xa0\xf6\xa3\x64\x4f\xca\x76\xa4\xb1\x75\x08\xc0\x03\xb0\x48\x0d\x8b\x17\x80\x0e\xfe\x69\xc8\x38\x21\xb5\x9d\x41\x64\x6a\x6c\xe6\xa2\x96\x23\xfb\x19\x6f\xd5\x77\x5c\x9f\xda\x9d\xfa\x8e\x4f\xb9\xff\x90\xfa\x30\xd5\xa9\xba\x3b\x7e\xf4\x14\xdd\xe7\xda\x0b\x1a\x4f\x31\x48\x3d\x24\xb4\xc9\x7d\x90\xd5\x07\xfb\x45\x0e\x75\xfc\xf1\x5e\xd0\x79\x7f\x40\x67\x7f\xdb\xf7\xed\xd6\x01\xba\x36\xf7\x5d\xca\x09\x0b\x6c\x1a\x39\xfb\xe1\xc3\xe3\x19\x75\x03\x27\x6c\xfd\xa7\x69\x9a\x1e\x07\xa8\x1c\x98\x1f\xe4\x38\x60\x70\x16\xaf\x44\xbd\x20\x10\xdc\x79\x67\x75\x50\x66\x19\x85\xd4\xe5\x2e\x71\x5c\x87\x06\x61\x62\x32\xb0\x21\x30\x34\xb9\x4d\x42\x1a\x71\xbc\x72\x7b\xe3\x86\xd4\x23\x0e\x50\x80\x7c\xcc\xf6\x40\xd4\x04\x66\x6c\x48\x91\x8a\x34\x54\xf0\xb7\xe0\x41\x44\x39\x4f\x5a\x2e\x70\xc7\x6c\x9f\x03\xa3\x0d\xf8\x74\x88\x93\xd8\x7a\x16\xb3\x9d\x40\xff\x2d\xe0\x66\x40\x19\x4f\xcc\x80\x7a\x6e\x10\x9a\x90\x2a\x42\xd7\x35\x23\x1a\x44\x5e\x68\xfa\xe0\xf3\xa1\x63\x32\x9b\x3a\x81\x87\xe3\x1d\xc6\x37\xa6\x47\x7d\xde\xf4\x3c\x9f\xdf\xcb\xd6\x61\x34\xe0\x1f\xf7\x7e\x00\x48\x28\x99\xd4\x44\x5d\x83\xcd\x39\x0d\x43\xf0\x2c\xb5\x6d\xda\x90\x57\xf6\x09\x85\xf3\x80\xf2\x70\x97\x55\x1c\x00\x14\xdd\x05\x28\x5d\x3b\x6a\x9a\xc0\xc0\x73\x01\x3e\x20\x6a\x61\x45\x87\xb2\x86\x21\x5f\xab\x7c\xf4\xad\x1c\x1f\xa1\xee\xfd\x1f\xf5\xd3\x51\x0f\x86\x51\x6f\x90\x9d\x8d\x7b\x73\xc5\xd6\x7c\x17\x77\xbb\xa6\x6e\xf5\x53\x3e\xd4\xb9\x87\x13\xbe\x78\x28\xcf\x24\x53\xfc\x9d\x9a\x6a\x66\x36\xfe\xf6\xd4\xd4\x71\x23\xee\x3c\x38\x44\x72\xfc\x7d\x62\x72\x4e\xdb\x9a\x15\xfa\x94\x61\x0a\xc5\xa2\x79\xae\x2b\xfd\xb7\xe2\xd1\x64\x8d\xd9\x97\x03\xee\xe1\x70\xb2\xee\xd2\x18\x0f\x21\x45\xeb\x2c\xe6\xb0\x26\xfd\xf8\x36\x38\x2f\x27\x6e\xe8\x51\xc6\xc6\x3a\xeb\x3b\xa1\xdd\x94\x7f\xe0\x19\xb8\xe0\xb1\xde\x5e\x9f\x01\xc1\x13\x2d\x38\x0f\x03\x1a\xb8\xff\x95\xe0\xcc\x8f\xa8\xfb\x70\xfd\x45\xc1\xf9\x5e\xf0\x60\x58\x70\x9f\x73\xea\x38\x9d\xe4\x8c\xfa\xee\x83\x92\x4f\xb5\xe4\x2e\x03\x4e\xee\x69\x10\x43\x51\x63\x8f\x40\x1c\x41\x8a\xd6\x92\x72\x58\xfd\x44\xf7\x40\xec\xd8\x10\x5a\x5a\x52\x1f\x90\x8b\x1e\xac\x94\xb3\xd9\xec\x64\xf7\x45\xd2\xe6\x4e\x09\xb2\x67\xf5\xb6\x59\x66\x3d\xb9\x74\x42\xc4\xdd\x5b\x38\x83\x10\x3c\x94\x98\x9c\xf9\xd4\x8b\x0e\x0a\x27\x86\xb9\xa9\xd6\xb8\xa2\x93\x1b\x59\x94\x69\x6a\x0c\x15\x53\x16\x05\x81\xa7\x21\xd2\x4d\x27\x84\xd4\xe4\x41\xca\xe4\xd4\x0f\xfb\xb5\xb4\x49\xcb\x98\x87\xa1\x5c\x82\x4f\x06\xc4\xe3\x1e\xf5\x36\x60\x85\xc0\x89\xc8\xd0\x65\x01\x79\xd8\xe3\x21\x19\xba\x6c\x4c\x4d\x73\x78\xc9\x4d\xfd\xb4\xed\x2e\x76\xdd\xfe\xe5\x23\x82\xaa\xca\xdf\xe5\x1e\x56\x58\x35\x40\x22\xde\xdd\x6f\xf3\x20\xe4\x3b\xdf\x8d\x76\x75\x06\xcd\xd1\x4b\x77\xf3\xe3\x92\xb3\xd7\x8d\x35\xba\xf9\xe1\xd7\xa8\x1c\x28\x02\x2b\xfe\x87\x55\x6d\x92\x7b\x3a\xbe\x5b\x55\x1b\x15\x9d\xd0\x27\x50\x85\x60\x48\x82\x55\x8a\x41\x21\xe2\x34\x8a\xa0\x3c\x71\x87\x72\xdb\x87\x9e\xe7\x87\x1c\x05\x62\x36\x33\x21\x38\xa0\x74\x39\xb0\x58\x0a\xec\xd0\xc5\x11\x91\x0f\x6b\x2d\x28\x5d\x50\xbb\x5c\xb8\x89\x24\x2e\x0f\x98\xe9\x78\x34\x0c\x82\xbc\x83\xa2\xd1\xf2\xe3\x1d\x49\x23\x0f\x8a\xd2\xaa\x3e\x90\x35\xb9\x4f\x56\x8f\x45\x10\xe4\xc4\x73\x02\x98\xc4\xb7\x5d\x1b\x66\x76\x60\xd2\x05\xd6\x4a\x3f\xcc\x6d\x6a\x07\x9e\x87\xa2\xf2\xc8\x4f\x50\x0f\x17\x92\x2a\x14\x64\x07\xd4\x71\xc0\x85\xa1\xc0\xba\x20\x71\x14\x9a\xb0\x38\x64\x2e\x08\x09\x0c\x43\xdf\x74\x02\x0a\x55\x1a\x28\x43\x06\xbc\xa1\x7e\x06\xa1\x67\x7a\x20\x72\x10\x98\x3e\x44\x00\xc0\x00\x10\x71\xe6\xde\x51\x80\x1d\xc9\x3e\x7d\x7a\x11\xfd\xb0\x22\x42\xa9\xf2\xaa\x57\x48\x75\xac\xaf\x57\x66\xf3\xe0\xfe\x78\xc7\x45\x0b\xc4\x3b\xa4\x31\xc6\x7b\xf1\xde\x20\x36\x10\xde\x9c\xbb\xac\xcd\x80\x0c\x06\x81\xf3\x82\x91\xfc\x80\x30\x58\x30\x3b\xde\xf8\x58\x37\x5b\xaf\xb4\x60\x21\xee\x62\x84\xbb\x90\x04\x6c\xb6\x30\x79\x48\x43\x1e\xb4\x97\x9c\xc1\x42\x82\xb9\x68\xfb\xc8\x87\x44\x31\xd0\x23\xba\xf7\xb1\x97\xe1\x8e\x10\x78\x59\x5e\x15\xf7\x60\x90\xc2\xa3\x3f\x0c\x05\xf3\x10\x06\xee\x05\xcd\x82\xff\x8b\xc2\xd0\x34\x76\x5b\xe9\x18\x37\xef\x2d\x38\xcd\xb9\x86\x54\x2d\xcd\x82\xb5\xc3\x6e\x6e\x40\xa5\xb9\x24\xdf\x81\xbf\x3d\x23\xdf\xe1\x89\x06\x39\x9f\x10\xfa\x93\x02\xf2\x44\xad\x97\xd3\x37\x62\x75\x7b\x1b\x8b\xf6\x34\xe2\xe6\x06\x29\x6f\x6f\x8d\x0b\x68\x15\xed\xb9\x88\x80\x4e\x36\x23\x85\x66\x43\x0c\xcb\xb8\xbd\xb5\x6e\x6e\x64\x91\xde\xde\xb6\x97\x56\xb4\x76\x5e\x7d\x30\xd1\x4a\x13\x2f\x45\x56\x74\xa7\x00\xd9\x86\x24\xb9\xa8\xa0\x2e\xe3\x09\x4b\x07\x7f\x73\x1f\x0d\x58\xad\x97\x4b\xa1\xb6\xbd\x22\xba\x12\x45\x7f\x84\x99\xd5\x72\x69\x5c\xc4\xd3\xe6\xdc\x66\xbd\x7c\x99\xa9\x0a\x45\x9c\x5e\x90\x34\xc3\x05\x6f\xa9\x1a\x59\xe5\xbf\x09\x23\x7b\x82\x2d\x88\x99\x57\xa0\x4c\x26\xab\x56\x62\x00\x0f\x78\x9f\x3c\x11\x2e\x5e\xbb\x99\xb0\xac\x76\x88\xe8\x59\xda\xa7\xc3\xbc\x6f\x6e\x4c\xa2\x89\x21\x94\x7e\x01\xb6\xd5\xeb\x6c\x09\xec\xd3\xcb\xb2\x05\xee\xfe\xf9\x47\xe5\x8c\x5c\x2d\xb2\x64\x41\xca\x22\xdf\x12\x2d\xce\x31\x8f\x46\x28\xa1\x24\x40\x50\xad\x72\xb1\x95\xe9\xf8\xae\x04\x7b\x33\xa1\x0b\x65\x9b\x9d\x37\xed\x9a\x3d\xe3\xe4\x59\x55\x67\xc5\x7c\x67\x9f\x5a\x4c\x61\xed\x2e\x54\x26\xcc\x54\x56\x89\xca\xa6\x32\x9d\x6e\x07\xec\x55\xef\x8e\xd7\x9a\x9e\xda\x67\xb7\x7a\xb1\xcf\xd2\x2d\x22\xa2\x48\xc9\x08\x2c\x45\xdf\x97\xaa\x26\x06\xba\x9b\x31\x26\x23\x00\x8a\xbe\x53\x78\x3a\x64\xe0\x64\xc6\x78\x87\x12\xb0\xe9\x1c\xf5\x2f\x15\x8c\x99\xe0\x90\xef\x4b\xa4\x9d\x20\x69\x67\x94\x01\x9c\xbf\xcf\xb1\x3d\x19\x40\xaf\xb5\x99\x71\x81\xc7\x80\xa4\x39\x3f\xeb\xd2\x35\x58\x60\xb7\x51\xa2\x2e\xf6\x0e\x4f\xd6\xf0\x68\xf0\xa7\x12\x36\x48\xcd\x89\x00\xc7\xba\x06\x71\x4f\x7c\x6a\x3b\x5e\x18\xc2\x36\xeb\x22\x86\xe5\xe7\xe1\x5a\x7a\x97\xa7\x2f\x62\x0b\x1e\x5e\xe8\x20\xc6\x20\x3b\x80\x07\xdd\xf5\x34\x8c\xc4\xc9\x10\x89\xff\x0d\x84\x7a\x59\xfc\x71\x8c\xbe\x9c\xe2\x77\xa7\xdf\x47\x14\x06\x52\xcf\xc1\x4f\x70\xf6\x2a\xfb\xf8\x54\x67\xc7\x21\x9f\xcd\xd9\xdf\x03\xb3\xaf\xdd\xd9\x07\x30\x7a\xc4\xd9\x7b\x10\x7d\xb2\xcd\xbf\x0c\x42\x9f\xc9\xd9\x3f\xb7\xe2\x4f\x73\xf6\xae\x6c\x2c\xb2\x54\x62\xa5\x30\x1e\xf3\xfe\x3a\x7b\x72\xaa\xc7\x21\x9f\xcd\xfb\xdf\x94\x69\x36\xcb\x64\xfa\xb5\x47\xc0\x00\x4e\x8f\x44\x40\x0f\xa6\x4f\x76\x84\x2f\x87\xd2\x67\x8a\x82\x3f\x42\xf9\xd3\x23\x01\xda\xaa\xd7\x3e\x5c\x09\xed\x5e\xd0\xed\x63\x82\xbe\x10\xc5\xab\xf2\xc3\x6a\xbf\x08\x3c\x58\x2f\xa5\x17\x77\xd5\xa4\xb4\x17\x5a\x87\x8b\xc6\x79\xb9\x5e\x19\x17\xaf\x4a\xb2\x5e\x1d\x2e\xfe\x50\x18\xd1\xdb\x65\xf6\x18\xe3\x24\xdf\x2f\x53\x51\x2d\x9e\x1f\xdf\xbf\x1b\xd2\x03\x84\x7d\x8d\x8f\xa1\xc1\xbe\xde\x7b\x68\x8c\x9f\xa0\x25\x98\xe5\xc3\xdf\x5f\xa3\x11\xf6\xba\x76\x98\xfd\x52\xc1\x8a\xbe\xe7\x01\x67\x07\xbe\x49\xbd\xbe\x77\xb2\x47\x9c\xb3\xd9\xc8\x85\xa1\xed\x10\x8e\x47\x7b\x41\xe4\x7a\x43\xce\xd9\xbe\x80\x3a\x70\xcc\x43\xc1\x8e\xbc\xf2\x53\x64\xe2\x3e\x9e\x55\x38\x21\x23\x3c\xa2\xcc\x75\x03\x7c\xf9\x36\x20\x13\x9e\xec\x3d\x24\x51\xdf\x49\x8f\x3c\xa5\x59\x43\xf6\xdf\x7b\x9f\xe8\x2d\xf7\x98\x00\x9d\x25\x15\xb0\x63\xd1\x81\x67\x98\x6c\xd0\x57\x06\x80\x3a\x1e\x09\x22\x61\xed\xd1\xbb\x4f\xfa\xb7\xf5\x52\x14\xba\x7f\x97\xcf\x41\x0c\x0e\x79\x6b\x8c\xb9\x00\xb9\x4b\x6c\x34\xbc\x1b\x86\x10\xd6\x97\xf8\xc4\xe0\x78\x4e\x83\x07\x50\xfc\x92\x79\xe7\xb6\x7b\x6e\x7b\xff\x34\xfa\x53\xef\x28\x6d\x66\xd9\x1c\x5f\x96\xfb\xc4\x76\x34\x25\xf9\xf5\x0d\x31\xed\xe0\xdc\xb6\x0d\xfd\xe1\xc0\x12\xcd\x70\x5a\x60\xc0\xb3\x5e\x32\x80\x1e\x0a\x7c\xbc\x1b\x8b\xad\xdd\xae\x39\x9e\x95\x65\xdd\xed\xec\xdf\x4b\xb5\x81\x84\x7c\x95\x41\xd1\x85\x78\x69\xbe\x29\x28\xca\x72\x25\x0b\xa8\x0d\x45\x09\xce\x21\x95\xc2\xb7\xa5\xda\x4f\xf0\x55\x7e\x75\x6e\x59\x89\x48\xd3\x6d\x85\x63\x15\x4d\x4a\xd8\x57\xbe\xc0\x1b\x68\x69\xaa\x67\xeb\xcd\x11\xe3\xfe\x6e\x55\x93\x7a\xbb\x02\xdc\x6a\x79\x5d\x5b\xff\x12\x1b\xa1\xef\xb6\x21\x39\x5b\x17\x09\xbe\xe8\x27\x79\x99\x88\x1c\x6c\xf4\xb2\x05\x7a\x24\xf1\x4b\x88\x54\x5e\x3f\x83\xdd\xe2\x98\xdc\x68\x25\xc1\x6b\x46\x92\x22\xab\x17\xfa\x13\x0a\x32\x99\x4c\xc8\x1a\xe8\x66\x59\x01\xbb\xd5\x8e\xee\x4c\xc9\x7a\xad\x8a\xe7\xba\xd7\x02\xb6\x11\x8a\xa4\x64\x02\x99\xfc\x8a\xe0\x34\xc0\x69\x2e\xeb\x1f\xeb\x1a\x76\xa1\x6b\xe8\xfe\xd0\x19\xf9\x87\xf1\xf8\xf9\x7e\xbe\xac\x7a\x2b\xde\x8e\xd2\xf1\x9e\xf9\x11\x93\x9e\x38\xdd\xb8\x7b\x06\x1e\x8a\xd5\xc9\xd5\x5e\x8e\xf4\x22\x29\xad\xcb\xd7\x88\x8a\x7c\x0f\x12\x16\xf3\x51\xcb\x5c\x93\xa3\x32\x28\xeb\x6b\xd8\x60\x03\xf1\x8f\x4a\x89\x2d\x5d\xa9\xb2\x2e\x11\x6e\x5a\xe5\x59\x22\x29\x0c\xce\x47\x69\x99\xac\x97\xc0\x12\x95\xfd\x39\x97\xd8\xac\x7e\xda\x5e\x8a\x39\x46\xed\xa8\x5d\x19\xb4\xbc\x3b\x8e\x74\x56\xaa\x9f\x45\xb2\x18\x1d\x9b\x45\xd3\x41\xa4\x37\x46\xd4\xdf\x8e\xb4\x4e\x18\x5b\xed\xa7\x31\xff\x09\x00\x00\xff\xff\x4b\xd9\xdc\xaa\x34\x23\x00\x00") - -func templateTmplBytes() ([]byte, error) { - return bindataRead( - _templateTmpl, - "template.tmpl", - ) + fi, err := os.Stat(path) + if err != nil { + err = fmt.Errorf("Error reading asset info %s at %s: %v", name, path, err) + } + + a := &asset{bytes: bytes, info: fi} + return a, err } +// templateTmpl reads file data from disk. It returns an error on failure. func templateTmpl() (*asset, error) { - bytes, err := templateTmplBytes() + path := "D:\\Code\\Go\\src\\github.com\\hacdias\\caddy-filemanager\\assets\\source\\template.tmpl" + name := "template.tmpl" + bytes, err := bindataRead(path, name) if err != nil { return nil, err } - info := bindataFileInfo{name: "template.tmpl", size: 9012, mode: os.FileMode(438), modTime: time.Unix(1465578153, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil + fi, err := os.Stat(path) + if err != nil { + err = fmt.Errorf("Error reading asset info %s at %s: %v", name, path, err) + } + + a := &asset{bytes: bytes, info: fi} + return a, err } // Asset loads and returns the asset for the given name. diff --git a/assets/source/template.tmpl b/assets/source/template.tmpl index 797ee967..e24a428d 100644 --- a/assets/source/template.tmpl +++ b/assets/source/template.tmpl @@ -5,9 +5,9 @@ - + diff --git a/fileinfo.go b/fileinfo.go new file mode 100644 index 00000000..f4380144 --- /dev/null +++ b/fileinfo.go @@ -0,0 +1,29 @@ +package filemanager + +import ( + "os" + "time" + + "github.com/dustin/go-humanize" +) + +// FileInfo is the info about a particular file or directory +type FileInfo struct { + IsDir bool + Name string + Size int64 + URL string + ModTime time.Time + Mode os.FileMode +} + +// HumanSize returns the size of the file as a human-readable string +// in IEC format (i.e. power of 2 or base 1024). +func (fi FileInfo) HumanSize() string { + return humanize.IBytes(uint64(fi.Size)) +} + +// HumanModTime returns the modified time of the file as a human-readable string. +func (fi FileInfo) HumanModTime(format string) string { + return fi.ModTime.Format(format) +} diff --git a/filemanager.go b/filemanager.go index 44db047b..db5f328f 100644 --- a/filemanager.go +++ b/filemanager.go @@ -1,6 +1,6 @@ //go:generate go get github.com/jteeuwen/go-bindata //go:generate go install github.com/jteeuwen/go-bindata/go-bindata -//go:generate go-bindata -pkg assets -prefix "assets/source" -o assets/assets.go assets/source/... +//go:generate go-bindata -debug -pkg assets -prefix "assets/source" -o assets/assets.go assets/source/... // Package filemanager provides middleware for managing files in a directory // when directory path is requested instead of a specific file. Based on browse @@ -10,22 +10,20 @@ package filemanager import ( "bytes" "encoding/json" - "mime" "net/http" "net/url" "os" "path" - "path/filepath" "strings" "text/template" - "time" - "github.com/dustin/go-humanize" - "github.com/hacdias/caddy-filemanager/assets" "github.com/mholt/caddy/caddyhttp/httpserver" "github.com/mholt/caddy/caddyhttp/staticfiles" ) +// Template used to show FileManager +var Template *template.Template + // FileManager is an http.Handler that can show a file listing when // directories in the given paths are specified. type FileManager struct { @@ -36,94 +34,11 @@ type FileManager struct { // Config is a configuration for browsing in a particular path. type Config struct { - PathScope string - Root http.FileSystem - Variables interface{} - Template *template.Template -} - -// A Listing is the context used to fill out a template. -type Listing struct { - // The name of the directory (the last element of the path) - Name string - - // The full path of the request - Path string - - // Whether the parent directory is browsable - CanGoUp bool - - // The items (files and folders) in the path - Items []FileInfo - - // The number of directories in the listing - NumDirs int - - // The number of files (items that aren't directories) in the listing - NumFiles int - - // Which sorting order is used - Sort string - - // And which order - Order string - - // If ≠0 then Items have been limited to that many elements - ItemsLimitedTo int - - // Optional custom variables for use in browse templates - User interface{} - - httpserver.Context -} - -// BreadcrumbMap returns l.Path where every element is a map -// of URLs and path segment names. -func (l Listing) BreadcrumbMap() map[string]string { - result := map[string]string{} - - if len(l.Path) == 0 { - return result - } - - // skip trailing slash - lpath := l.Path - if lpath[len(lpath)-1] == '/' { - lpath = lpath[:len(lpath)-1] - } - - parts := strings.Split(lpath, "/") - for i, part := range parts { - if i == 0 && part == "" { - // Leading slash (root) - result["/"] = "/" - continue - } - result[strings.Join(parts[:i+1], "/")] = part - } - - return result -} - -// FileInfo is the info about a particular file or directory -type FileInfo struct { - IsDir bool - Name string - Size int64 - URL string - ModTime time.Time - Mode os.FileMode -} - -// HumanSize returns the size of the file as a human-readable string -// in IEC format (i.e. power of 2 or base 1024). -func (fi FileInfo) HumanSize() string { - return humanize.IBytes(uint64(fi.Size)) -} - -// HumanModTime returns the modified time of the file as a human-readable string. -func (fi FileInfo) HumanModTime(format string) string { - return fi.ModTime.Format(format) + PathScope string + Root http.FileSystem + BaseURL string + StyleSheet string + Variables interface{} } func directoryListing(files []os.FileInfo, canGoUp bool, urlPath string) (Listing, bool) { @@ -175,64 +90,62 @@ func directoryListing(files []os.FileInfo, canGoUp bool, urlPath string) (Listin // ServeHTTP determines if the request is for this plugin, and if all prerequisites are met. // If so, control is handed over to ServeListing. func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { - var bc *Config + var fmc *Config // See if there's a browse configuration to match the path for i := range f.Configs { - if httpserver.Path(r.URL.Path).Matches(f.Configs[i].PathScope) { - bc = &f.Configs[i] - goto inScope + if httpserver.Path(r.URL.Path).Matches(f.Configs[i].BaseURL) { + fmc = &f.Configs[i] + + // Browse works on existing directories; delegate everything else + requestedFilepath, err := fmc.Root.Open(strings.Replace(r.URL.Path, fmc.BaseURL, "", 1)) + if err != nil { + switch { + case os.IsPermission(err): + return http.StatusForbidden, err + case os.IsExist(err): + return http.StatusNotFound, err + default: + return f.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 f.Next.ServeHTTP(w, r) + } + } + if !info.IsDir() { + return f.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 f.Next.ServeHTTP(w, r) + } + + // Browsing navigation gets messed up if browsing a directory + // that doesn't end in "/" (which it should, anyway) + if !strings.HasSuffix(r.URL.Path, "/") { + http.Redirect(w, r, r.URL.Path+"/", http.StatusTemporaryRedirect) + return 0, nil + } + + return f.ServeListing(w, r, requestedFilepath, fmc) } } return f.Next.ServeHTTP(w, r) -inScope: - - // Browse works on existing directories; delegate everything else - requestedFilepath, err := bc.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 f.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 f.Next.ServeHTTP(w, r) - } - } - if !info.IsDir() { - return f.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 f.Next.ServeHTTP(w, r) - } - - // Browsing navigation gets messed up if browsing a directory - // that doesn't end in "/" (which it should, anyway) - if !strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, r, r.URL.Path+"/", http.StatusTemporaryRedirect) - return 0, nil - } - - return f.ServeListing(w, r, requestedFilepath, bc) } func (f FileManager) loadDirectoryContents(requestedFilepath http.File, urlPath string) (*Listing, bool, error) { @@ -316,26 +229,6 @@ func (f FileManager) ServeListing(w http.ResponseWriter, r *http.Request, reques return http.StatusOK, nil } -// serveAssets handles the /{admin}/assets requests -func serveAssets(w http.ResponseWriter, r *http.Request) (int, error) { - filename := strings.Replace(r.URL.Path, assetsURL, "", 1) - file, err := assets.Asset(filename) - - if err != nil { - return 404, nil - } - - // Get the file extension ant its mime type - extension := filepath.Ext(filename) - mime := mime.TypeByExtension(extension) - - // Write the header with the Content-Type and write the file - // content to the buffer - w.Header().Set("Content-Type", mime) - w.Write(file) - return 200, nil -} - func (f FileManager) formatAsJSON(listing *Listing, bc *Config) (*bytes.Buffer, error) { marsh, err := json.Marshal(listing.Items) if err != nil { @@ -349,6 +242,6 @@ func (f FileManager) formatAsJSON(listing *Listing, bc *Config) (*bytes.Buffer, func (f FileManager) formatAsHTML(listing *Listing, bc *Config) (*bytes.Buffer, error) { buf := new(bytes.Buffer) - err := bc.Template.Execute(buf, listing) + err := Template.Execute(buf, listing) return buf, err } diff --git a/listing.go b/listing.go new file mode 100644 index 00000000..a7a2e1e1 --- /dev/null +++ b/listing.go @@ -0,0 +1,73 @@ +package filemanager + +import ( + "strings" + + "github.com/mholt/caddy/caddyhttp/httpserver" +) + +// A Listing is the context used to fill out a template. +type Listing struct { + // The name of the directory (the last element of the path) + Name string + + // The full path of the request + Path string + + // Whether the parent directory is browsable + CanGoUp bool + + // The items (files and folders) in the path + Items []FileInfo + + // The number of directories in the listing + NumDirs int + + // The number of files (items that aren't directories) in the listing + NumFiles int + + // Which sorting order is used + Sort string + + // And which order + Order string + + // If ≠0 then Items have been limited to that many elements + ItemsLimitedTo int + + // Optional custom variables for use in browse templates + User interface{} + + // StyleSheet to costumize the page + StyleSheet string + + httpserver.Context +} + +// BreadcrumbMap returns l.Path where every element is a map +// of URLs and path segment names. +func (l Listing) BreadcrumbMap() map[string]string { + result := map[string]string{} + + if len(l.Path) == 0 { + return result + } + + // skip trailing slash + lpath := l.Path + if lpath[len(lpath)-1] == '/' { + lpath = lpath[:len(lpath)-1] + } + + parts := strings.Split(lpath, "/") + for i, part := range parts { + if i == 0 && part == "" { + // Leading slash (root) + result["/"] = "/" + continue + } + result[strings.Join(parts[:i+1], "/")] = part + } + + return result +} diff --git a/setup.go b/setup.go index 1d5615e3..b66a4e94 100644 --- a/setup.go +++ b/setup.go @@ -22,6 +22,20 @@ func init() { // setup configures a new Browse middleware instance. func setup(c *caddy.Controller) error { + // Second argument would be the template file to use + tplBytes, err := assets.Asset("template.tmpl") + if err != nil { + return err + } + tplText := string(tplBytes) + + // Build the template + tpl, err := template.New("listing").Parse(tplText) + if err != nil { + return err + } + Template = tpl + configs, err := fileManagerParse(c) if err != nil { return err @@ -43,65 +57,63 @@ func setup(c *caddy.Controller) error { func fileManagerParse(c *caddy.Controller) ([]Config, error) { var configs []Config - cfg := httpserver.GetConfig(c.Key) - - appendCfg := func(bc Config) error { + appendCfg := func(fmc Config) error { for _, c := range configs { - if c.PathScope == bc.PathScope { - return fmt.Errorf("duplicate browsing config for %s", c.PathScope) + if c.PathScope == fmc.PathScope { + return fmt.Errorf("duplicate file managing config for %s", c.PathScope) } } - configs = append(configs, bc) + configs = append(configs, fmc) return nil } for c.Next() { - var bc Config + var fmc = Config{ + PathScope: ".", + BaseURL: "/", + StyleSheet: "", + } + var styles string - // First argument is directory to allow browsing; default is site root - if c.NextArg() { - bc.PathScope = c.Val() - } else { - bc.PathScope = "/" - } - bc.Root = http.Dir(cfg.Root) - theRoot, err := bc.Root.Open("/") // catch a missing path early - if err != nil { - return configs, err - } - defer theRoot.Close() - _, err = theRoot.Readdir(-1) - if err != nil { - return configs, err + for c.NextBlock() { + switch c.Val() { + case "show": + if !c.NextArg() { + return configs, c.ArgErr() + } + fmc.PathScope = c.Val() + case "on": + if !c.NextArg() { + return configs, c.ArgErr() + } + fmc.BaseURL = c.Val() + case "styles": + if !c.NextArg() { + return configs, c.ArgErr() + } + styles = c.Val() + } } - var tplBytes []byte - - // Second argument would be the template file to use - var tplText string - if c.NextArg() { - tplBytes, err = ioutil.ReadFile(c.Val()) + // Get StyleSheet + if styles != "" { + tplBytes, err := ioutil.ReadFile(c.Val()) if err != nil { return configs, err } - tplText = string(tplBytes) + fmc.StyleSheet = string(tplBytes) } else { - tplBytes, err = assets.Asset(assetsURL + "template.tmpl") + tplBytes, err := assets.Asset("template.tmpl") if err != nil { return configs, err } - tplText = string(tplBytes) + fmc.StyleSheet = string(tplBytes) } - // Build the template - tpl, err := template.New("listing").Parse(tplText) - if err != nil { - return configs, err - } - bc.Template = tpl + fmc.Root = http.Dir(fmc.PathScope) // Save configuration - err = appendCfg(bc) + err := appendCfg(fmc) if err != nil { return configs, err }