mirror of
https://github.com/hamburghammer/gohttpserver.git
synced 2025-03-15 07:45:57 +01:00
finish two features
This commit is contained in:
parent
bbb1b03f7a
commit
8b129b517b
13 changed files with 129 additions and 3 deletions
|
@ -16,8 +16,8 @@ If using go1.5, ensure you set GO15VENDOREXPERIMENT=1
|
||||||
1. [x] HTTP Basic Auth
|
1. [x] HTTP Basic Auth
|
||||||
1. [ ] \.htaccess support
|
1. [ ] \.htaccess support
|
||||||
1. [x] Partial reload pages when directory change
|
1. [x] Partial reload pages when directory change
|
||||||
1. [ ] When only one dir under dir, path will combine two together
|
1. [x] When only one dir under dir, path will combine two together
|
||||||
1. [ ] Directory zip download
|
1. [x] Directory zip download
|
||||||
1. [ ] Apple ipa auto generate .plist file, qrcode can be recognized by iphone (Require https)
|
1. [ ] Apple ipa auto generate .plist file, qrcode can be recognized by iphone (Require https)
|
||||||
1. [ ] Support modify the index page
|
1. [ ] Support modify the index page
|
||||||
1. [ ] Download count statistics
|
1. [ ] Download count statistics
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -27,6 +28,7 @@ func NewHTTPStaticServer(root string) *HTTPStaticServer {
|
||||||
m: m,
|
m: m,
|
||||||
}
|
}
|
||||||
m.HandleFunc("/-/raw/{path:.*}", s.hFileOrDirectory)
|
m.HandleFunc("/-/raw/{path:.*}", s.hFileOrDirectory)
|
||||||
|
m.HandleFunc("/-/zip/{path:.*}", s.hZip)
|
||||||
m.HandleFunc("/-/json/{path:.*}", s.hJSONList)
|
m.HandleFunc("/-/json/{path:.*}", s.hJSONList)
|
||||||
m.HandleFunc("/{path:.*}", s.hIndex).Methods("GET")
|
m.HandleFunc("/{path:.*}", s.hIndex).Methods("GET")
|
||||||
return s
|
return s
|
||||||
|
@ -47,6 +49,11 @@ func (s *HTTPStaticServer) hIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *HTTPStaticServer) hZip(w http.ResponseWriter, r *http.Request) {
|
||||||
|
path := mux.Vars(r)["path"]
|
||||||
|
CompressToZip(w, path)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *HTTPStaticServer) hFileOrDirectory(w http.ResponseWriter, r *http.Request) {
|
func (s *HTTPStaticServer) hFileOrDirectory(w http.ResponseWriter, r *http.Request) {
|
||||||
path := mux.Vars(r)["path"]
|
path := mux.Vars(r)["path"]
|
||||||
log.Println("Path:", s.Root, path)
|
log.Println("Path:", s.Root, path)
|
||||||
|
@ -81,6 +88,9 @@ func (s *HTTPStaticServer) hJSONList(w http.ResponseWriter, r *http.Request) {
|
||||||
Path: filepath.Join(path, file.Name()), // lstrip "/"
|
Path: filepath.Join(path, file.Name()), // lstrip "/"
|
||||||
}
|
}
|
||||||
if file.IsDir() {
|
if file.IsDir() {
|
||||||
|
fileName := deepPath(filepath.Join(s.Root, path), file.Name())
|
||||||
|
lr.Name = fileName
|
||||||
|
lr.Path = filepath.Join(path, fileName)
|
||||||
lr.Type = "dir"
|
lr.Type = "dir"
|
||||||
lr.Size = "-"
|
lr.Size = "-"
|
||||||
} else {
|
} else {
|
||||||
|
@ -94,3 +104,21 @@ func (s *HTTPStaticServer) hJSONList(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Write(data)
|
w.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deepPath(basedir, name string) string {
|
||||||
|
isDir := true
|
||||||
|
// loop max 5, incase of for loop not finished
|
||||||
|
maxDepth := 5
|
||||||
|
for depth := 0; depth <= maxDepth && isDir; depth += 1 {
|
||||||
|
finfos, err := ioutil.ReadDir(filepath.Join(basedir, name))
|
||||||
|
if err != nil || len(finfos) != 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if finfos[0].IsDir() {
|
||||||
|
name = filepath.Join(name, finfos[0].Name())
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
|
@ -87,6 +87,12 @@
|
||||||
</td>
|
</td>
|
||||||
<td>{{f.size}}</td>
|
<td>{{f.size}}</td>
|
||||||
<td style="text-align: center">
|
<td style="text-align: center">
|
||||||
|
<template v-if="f.type == 'dir'">
|
||||||
|
<a class="btn btn-default btn-xs" href="/-/zip/{{f.path}}">
|
||||||
|
Archieve Zip
|
||||||
|
<span class="glyphicon glyphicon-download-alt"></span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
<template v-if="f.type == 'file'">
|
<template v-if="f.type == 'file'">
|
||||||
<a class="btn btn-default btn-xs" href="/-/raw/{{f.path}}?download=true">
|
<a class="btn btn-default btn-xs" href="/-/raw/{{f.path}}?download=true">
|
||||||
<span class="hidden-xs">Download</span>
|
<span class="hidden-xs">Download</span>
|
||||||
|
|
|
@ -94,7 +94,7 @@ var vm = new Vue({
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
},
|
},
|
||||||
updateBreadcrumb: function() {
|
updateBreadcrumb: function() {
|
||||||
var pathname = location.pathname || "/";
|
var pathname = decodeURI(location.pathname || "/");
|
||||||
var parts = pathname.split('/');
|
var parts = pathname.split('/');
|
||||||
this.breadcrumb = [];
|
this.breadcrumb = [];
|
||||||
if (pathname == "/") {
|
if (pathname == "/") {
|
||||||
|
|
0
testdata/deep1/deep2/deep3/.gitkeep
vendored
Normal file
0
testdata/deep1/deep2/deep3/.gitkeep
vendored
Normal file
0
testdata/filetypes/code.go
vendored
Normal file
0
testdata/filetypes/code.go
vendored
Normal file
0
testdata/filetypes/image.jpeg
vendored
Normal file
0
testdata/filetypes/image.jpeg
vendored
Normal file
0
testdata/filetypes/image.jpg
vendored
Normal file
0
testdata/filetypes/image.jpg
vendored
Normal file
0
testdata/filetypes/image.pdf
vendored
Normal file
0
testdata/filetypes/image.pdf
vendored
Normal file
0
testdata/filetypes/image.png
vendored
Normal file
0
testdata/filetypes/image.png
vendored
Normal file
0
testdata/filetypes/image.tiff
vendored
Normal file
0
testdata/filetypes/image.tiff
vendored
Normal file
0
testdata/中文路径/.gitkeep
vendored
Normal file
0
testdata/中文路径/.gitkeep
vendored
Normal file
92
zip.go
Normal file
92
zip.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Zip struct {
|
||||||
|
*zip.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizedName(filename string) string {
|
||||||
|
if len(filename) > 1 && filename[1] == ':' &&
|
||||||
|
runtime.GOOS == "windows" {
|
||||||
|
filename = filename[2:]
|
||||||
|
}
|
||||||
|
filename = strings.TrimLeft(strings.Replace(filename, `\`, "/", -1), `/`)
|
||||||
|
filename = filepath.ToSlash(filename)
|
||||||
|
filename = filepath.Clean(filename)
|
||||||
|
return filename
|
||||||
|
}
|
||||||
|
|
||||||
|
func statFile(filename string) (info os.FileInfo, reader io.ReadCloser, err error) {
|
||||||
|
info, err = os.Lstat(filename)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// content
|
||||||
|
if info.Mode()&os.ModeSymlink != 0 {
|
||||||
|
var target string
|
||||||
|
target, err = os.Readlink(filename)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reader = ioutil.NopCloser(bytes.NewBuffer([]byte(target)))
|
||||||
|
} else if !info.IsDir() {
|
||||||
|
reader, err = os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reader = ioutil.NopCloser(bytes.NewBuffer(nil))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *Zip) Add(relpath, abspath string) error {
|
||||||
|
info, rdc, err := statFile(abspath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer rdc.Close()
|
||||||
|
|
||||||
|
hdr, err := zip.FileInfoHeader(info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hdr.Name = sanitizedName(relpath)
|
||||||
|
if info.IsDir() {
|
||||||
|
hdr.Name += "/"
|
||||||
|
}
|
||||||
|
hdr.Method = zip.Deflate // compress method
|
||||||
|
writer, err := z.CreateHeader(hdr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(writer, rdc)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompressToZip(w http.ResponseWriter, rootDir string) {
|
||||||
|
rootDir = filepath.Clean(rootDir)
|
||||||
|
zipFileName := filepath.Base(rootDir) + ".zip"
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/zip")
|
||||||
|
w.Header().Set("Content-Disposition", `attachment; filename="`+zipFileName+`"`)
|
||||||
|
|
||||||
|
zw := &Zip{Writer: zip.NewWriter(w)}
|
||||||
|
defer zw.Close()
|
||||||
|
|
||||||
|
filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
zipPath := path[len(rootDir):]
|
||||||
|
return zw.Add(zipPath, path)
|
||||||
|
})
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue