Compare commits

...

28 commits

Author SHA1 Message Date
Augusto Dwenger J. 627dea49c5 Add docker setup section to the README 2021-04-01 11:31:01 +02:00
Augusto Dwenger 777ff2376d Merge remote-tracking branch 'upstream/master'
Following features where merged:
 - Add support delete non-empty folder.
 - Add Cyan theme.
 - Sync status bar color with border-color on mobile platforms.

There are also some other changes but I am not able to understand them
from there commit message...
* upstream/master:
  update readme
  merge pull request
  Fix the assignment of sync buf
  update docker badge
  Optimize the performance of the copy phase during the upload process
  support delete non-empty folder, close #97
  update readme
  fix goreleaser again
  fix goreleaser again
  fix goreleaser
  fix upload large file >32M, close #98
  Update travis.yml
  Edit README.
  Add Cyan theme.
  Sync status bar color with border-color on mobile platforms.
  Use Go 1.14 & Update copyright string.
  fix: 修复问题
  fix: 修复问题
  fix: issue#49
2021-04-01 10:33:57 +02:00
codeskyblue 41981a3d8a update readme 2021-04-01 11:16:51 +08:00
codeskyblue 47789eec68 Merge branch 'aeoluswing-master' 2021-03-30 17:04:43 +08:00
codeskyblue 4c880193ce merge pull request 2021-03-30 17:04:23 +08:00
codeskyblue 86aeecfac2 Merge branch 'master' of https://github.com/aeoluswing/gohttpserver into aeoluswing-master 2021-03-30 16:47:34 +08:00
aeolus e8af97872c
Merge pull request #2 from aeoluswing/fix-uplimit-20210326
Fix the assignment of sync buf
2021-03-26 18:58:16 +08:00
aeoluswing d7590729f1 Fix the assignment of sync buf 2021-03-26 18:50:06 +08:00
codeskyblue f7063651c2 update docker badge 2021-03-26 15:57:47 +08:00
codeskyblue 42d1e077c9 merge theme 2021-03-26 15:41:28 +08:00
aeolus 1258ac759f
Merge pull request #1 from aeoluswing/fix-uplimit-20210326
Optimize the performance of the copy phase during the upload process
2021-03-26 14:18:29 +08:00
aeoluswing a60a9c4811 Optimize the performance of the copy phase during the upload process 2021-03-26 14:03:54 +08:00
codeskyblue b6200a88c0 support delete non-empty folder, close #97 2021-03-24 22:23:09 +08:00
codeskyblue 1618440f4f update readme 2021-03-24 15:02:18 +08:00
codeskyblue f676d25787 fix goreleaser again 2021-03-24 11:18:55 +08:00
codeskyblue e24ff056f7 fix goreleaser again 2021-03-24 11:09:37 +08:00
codeskyblue 833443dfaf fix goreleaser 2021-03-24 11:06:45 +08:00
codeskyblue b6f8563d18 Merge branch 'mahuiplus-master' 2021-03-24 10:38:52 +08:00
codeskyblue 20ed231c53 Merge branch 'master' of https://github.com/mahuiplus/gohttpserver into mahuiplus-master 2021-03-24 10:36:52 +08:00
codeskyblue b4470cf4bd fix upload large file >32M, close #98 2021-03-23 22:26:42 +08:00
hathlife 5367b9ea94 Update travis.yml 2020-04-27 15:53:43 +08:00
hathlife 8e275e27be Edit README. 2020-04-27 15:40:54 +08:00
hathlife 56e184748f Add Cyan theme. 2020-04-27 15:40:54 +08:00
hathlife b40bf8101f Sync status bar color with border-color on mobile platforms. 2020-04-27 15:40:30 +08:00
hathlife 70e364c57b Use Go 1.14 & Update copyright string. 2020-03-25 21:21:36 +08:00
MaHui 98b09cb27f fix: 修复问题 2019-08-10 12:21:51 +08:00
MaHui aad95ae813 fix: 修复问题 2019-08-08 08:38:53 +08:00
MaHui 2bd7ec5cd0 fix: issue#49 2019-08-05 19:09:14 +08:00
10 changed files with 166 additions and 61 deletions

2
.gitignore vendored
View file

@ -29,3 +29,5 @@ bindata_assetfs.go
assets_vfsdata.go
*.un~
*.swp
dist/

View file

@ -1,7 +1,6 @@
# gohttpserver
This is a fork from [codeskyblue/gohttpserver](https://github.com/codeskyblue/gohttpserver/) without google-analytics.
- Goal: Make the best HTTP File Server.
- Features: Human-friendly UI, file uploading support, direct QR-code generation for Apple & Android install package.
@ -12,7 +11,7 @@ This is a fork from [codeskyblue/gohttpserver](https://github.com/codeskyblue/go
## Requirements
Tested with go-1.10, go-1.11
Tested with go-1.16
## Screenshots
![screen](testdata/filetypes/gohttpserver.gif)
@ -62,7 +61,6 @@ go get -v github.com/codeskyblue/gohttpserver
cd $GOPATH/src/github.com/codeskyblue/gohttpserver
go build && ./gohttpserver
```
## Usage
Listen on port 8000 of all interfaces, and enable file uploading.
@ -72,6 +70,36 @@ Listen on port 8000 of all interfaces, and enable file uploading.
Use command `gohttpserver --help` to see more usage.
## Docker Usage
share current directory
```bash
docker run -it --rm -p 8000:8000 -v $PWD:/app/public --name gohttpserver registry.hhhammer.de/gohttpserver
```
Share current directory with http basic auth
```bash
docker run -it --rm -p 8000:8000 -v $PWD:/app/public --name gohttpserver \
registry.hhhammer.de/gohttpserver \
--auth-type http --auth-http username:password
```
Share current directory with openid auth. (Works only in netease company.)
```bash
docker run -it --rm -p 8000:8000 -v $PWD:/app/public --name gohttpserver \
registry.hhhammer.de/gohttpserver \
--auth-type openid
```
To build image yourself, please change the PWD to the root of this repo.
```bash
cd gohttpserver/
docker build -t registry.hhhhammer.de/gohttpserver -f docker/Dockerfile .
```
## Authentication options
- Enable basic http authentication
@ -93,7 +121,7 @@ Use command `gohttpserver --help` to see more usage.
You can configure to let a http reverse proxy handling authentication.
When using oauth2-proxy, the backend will use identification info from request headers `X-Auth-Request-Email` as userId and `X-Auth-Request-Fullname` as user's display name.
Please config your oauth2 reverse proxy yourself.
More about [oauth2-proxy](https://github.com/bitly/oauth2_proxy).
More about [oauth2-proxy](https://github.com/oauth2-proxy/oauth2-proxy).
All required headers list as following.

View file

@ -4,6 +4,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="theme-color" content="#000000">
<title>[[.Title]]</title>
<link rel="shortcut icon" type="image/png" href="/-/assets/favicon.png" />
<link rel="stylesheet" type="text/css" href="/-/assets/bootstrap-3.3.5/css/bootstrap.min.css">
@ -128,7 +129,7 @@
<tbody>
<tr v-for="f in computedFiles">
<td>
<a v-on:click='clickFileOrDir(f, $event)' href="/{{f.path + (f.type == 'dir' ? '' : '')}}">
<a v-on:click='clickFileOrDir(f, $event)' href="{{getEncodePath(f)}}">
<!-- ?raw=false -->
<i style="padding-right: 0.5em" class="fa" v-bind:class='genFileClass(f)'></i> {{f.name}}
</a>
@ -141,7 +142,7 @@
<td class="hidden-xs">{{formatTime(f.mtime)}}</td>
<td style="text-align: left">
<template v-if="f.type == 'dir'">
<a class="btn btn-default btn-xs" href="/{{f.path}}/?op=archive">
<a class="btn btn-default btn-xs" href="{{getEncodePath(f)}}/?op=archive">
<span class="hidden-xs">Archive</span> Zip
<span class="glyphicon glyphicon-download-alt"></span>
</a>
@ -273,6 +274,28 @@
<script src="/-/assets/bootstrap-3.3.5/js/bootstrap.min.js"></script>
<script src='/-/assets/[["js/index.js" | urlhash ]]'></script>
<!-- <script src="/-/assets/js/index.js"></script> -->
<!--Sync status bar color with border-color on mobile platforms.-->
<script>
var META = document.getElementsByTagName("meta");
META[2]["content"]=$('.navbar').css('border-color');
</script>
[[if .GoogleTrackerID ]]
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
ga('create', '[[.GoogleTrackerID]]', 'auto');
ga('send', 'pageview');
</script> [[ end ]]
</body>
</html>
</html>

View file

@ -30,7 +30,7 @@ function checkPathNameLegal(name) {
function showErrorMessage(jqXHR) {
let errMsg = jqXHR.getResponseHeader("x-auth-authentication-message")
if (errMsg == null) {
errMsg = jqXHR.responseText
errMsg = jqXHR.responseText
}
alert(String(jqXHR.status).concat(":", errMsg));
console.error(errMsg)
@ -141,6 +141,9 @@ var vm = new Vue({
});
},
methods: {
getEncodePath: function (f) {
return pathJoin([location.pathname, encodeURIComponent(f.name)]);
},
formatTime: function (timestamp) {
var m = moment(timestamp);
if (this.mtimeTypeFromNow) {
@ -167,7 +170,7 @@ var vm = new Vue({
if (!name) {
parts.push(pathname);
} else if (getExtention(name) == "ipa") {
parts.push("/-/ipa/link", pathname, name);
parts.push("/-/ipa/link", pathname, encodeURIComponent(name));
} else {
parts.push(pathname, name);
}
@ -188,7 +191,7 @@ var vm = new Vue({
genDownloadURL: function (f) {
var search = location.search;
var sep = search == "" ? "?" : "&"
return location.origin + "/" + f.path + location.search + sep + "download=true";
return location.origin + this.getEncodePath(f) + location.search + sep + "download=true";
},
shouldHaveQrcode: function (name) {
return ['apk', 'ipa'].indexOf(getExtention(name)) !== -1;
@ -234,11 +237,12 @@ var vm = new Vue({
return "fa-file-text-o"
},
clickFileOrDir: function (f, e) {
var reqPath = pathJoin([location.pathname, encodeURIComponent(f.name)]);
// TODO: fix here tomorrow
if (f.type == "file") {
return true;
window.location.href = reqPath;
return;
}
var reqPath = pathJoin([location.pathname, f.name]);
loadFileOrDir(reqPath);
e.preventDefault()
},
@ -249,7 +253,7 @@ var vm = new Vue({
showInfo: function (f) {
console.log(f);
$.ajax({
url: pathJoin(["/", location.pathname, f.name]),
url: pathJoin(["/", location.pathname, encodeURIComponent(f.name)]),
data: {
op: "info",
},
@ -276,7 +280,7 @@ var vm = new Vue({
return
}
$.ajax({
url: pathJoin(["/", location.pathname, "/", name]),
url: pathJoin(["/", location.pathname, "/", encodeURIComponent(name)]),
method: "POST",
success: function (res) {
console.log(res)
@ -295,7 +299,7 @@ var vm = new Vue({
}
}
$.ajax({
url: pathJoin([location.pathname, f.name]),
url: pathJoin([location.pathname, encodeURIComponent(f.name)]),
method: 'DELETE',
success: function (res) {
loadFileList()
@ -333,23 +337,23 @@ var vm = new Vue({
}
var that = this;
$.getJSON(pathJoin(['/-/info', location.pathname]))
.then(function (res) {
console.log(res);
that.preview.filename = res.name;
that.preview.filesize = res.size;
return $.ajax({
url: '/' + res.path,
dataType: 'text',
.then(function (res) {
console.log(res);
that.preview.filename = res.name;
that.preview.filesize = res.size;
return $.ajax({
url: '/' + res.path,
dataType: 'text',
});
})
.then(function (res) {
console.log(res)
that.preview.contentHTML = '<pre>' + res + '</pre>';
console.log("Finally")
})
.done(function (res) {
console.log("done", res)
});
})
.then(function (res) {
console.log(res)
that.preview.contentHTML = '<pre>' + res + '</pre>';
console.log("Finally")
})
.done(function (res) {
console.log("done", res)
});
},
loadAll: function () {
// TODO: move loadFileList here
@ -440,10 +444,10 @@ $(function () {
console.info('Text:', e.text);
console.info('Trigger:', e.trigger);
$(e.trigger)
.tooltip('show')
.mouseleave(function () {
$(this).tooltip('hide');
})
.tooltip('show')
.mouseleave(function () {
$(this).tooltip('hide');
})
e.clearSelection();
});

31
assets/themes/cyan.css Normal file
View file

@ -0,0 +1,31 @@
body {}
td>a:hover {
color: #4cc0cf;
font-weight: normal;
}
td>a {
color: rgb(51, 51, 51);
}
a:hover {
font-weight: bold;
}
.navbar {
background-color: #00BCD4;
border-color: #0097A7;
}
.navbar .navbar-brand {
color: white;
}
.navbar {
border-radius: 0px;
}
.navbar-default ul.navbar-nav>li>a {
color: white;
}

View file

@ -1,4 +1,4 @@
FROM golang:1.15.6
FROM golang:1.16
WORKDIR /appsrc/gohttpserver
ADD . /appsrc/gohttpserver
RUN GOOS=linux GOARCH=arm go build -ldflags '-X main.VERSION=docker' -o gohttpserver .

View file

@ -9,8 +9,12 @@ fi
set -ex
sed -i '/experimental/d' $HOME/.docker/config.json
sed -i '1a"experimental": "enabled",' $HOME/.docker/config.json
if test $(uname) = "Linux"
then
sed -i '/experimental/d' $HOME/.docker/config.json
sed -i '1a"experimental": "enabled",' $HOME/.docker/config.json
fi
docker manifest create codeskyblue/gohttpserver \
codeskyblue/gohttpserver:latest \
codeskyblue/gohttpserver:armhf
@ -21,4 +25,4 @@ docker manifest annotate codeskyblue/gohttpserver \
docker manifest push codeskyblue/gohttpserver
# check again
docker run mplatform/mquery codeskyblue/gohttpserver
docker run mplatform/mquery codeskyblue/gohttpserver

6
go.mod
View file

@ -1,5 +1,7 @@
module github.com/hamburghammer/gohttpserver
go 1.16
require (
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect
@ -20,8 +22,6 @@ require (
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.3.0
golang.org/x/text v0.3.3
golang.org/x/tools v0.0.0-20201204222352-654352759326 // indirect
golang.org/x/tools v0.1.0 // indirect
howett.net/plist v0.0.0-20201203080718-1454fab16a06 // indirect
)
go 1.13

6
go.sum
View file

@ -70,15 +70,15 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201204222352-654352759326 h1:XKLw9EEEfGJFE2K5Ni4nXgtFBIfI+zKPIi2SlRYmIG4=
golang.org/x/tools v0.0.0-20201204222352-654352759326/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View file

@ -16,6 +16,7 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"regexp"
@ -52,6 +53,7 @@ type HTTPStaticServer struct {
indexes []IndexFileItem
m *mux.Router
bufPool sync.Pool // use sync.Pool caching buf to reduce gc ratio
}
func NewHTTPStaticServer(root string) *HTTPStaticServer {
@ -68,6 +70,9 @@ func NewHTTPStaticServer(root string) *HTTPStaticServer {
Root: root,
Theme: "black",
m: m,
bufPool: sync.Pool{
New: func() interface{} { return make([]byte, 32*1024) },
},
}
go func() {
@ -157,15 +162,16 @@ func (s *HTTPStaticServer) hMkdir(w http.ResponseWriter, req *http.Request) {
}
func (s *HTTPStaticServer) hDelete(w http.ResponseWriter, req *http.Request) {
// only can delete file now
path := mux.Vars(req)["path"]
path = filepath.Clean(path) // for safe reason, prevent path contain ..
auth := s.readAccessConf(path)
if !auth.canDelete(req) {
http.Error(w, "Delete forbidden", http.StatusForbidden)
return
}
err := os.Remove(filepath.Join(s.Root, path))
// TODO: path safe check
err := os.RemoveAll(filepath.Join(s.Root, path))
if err != nil {
pathErr, ok := err.(*os.PathError)
if ok {
@ -231,22 +237,29 @@ func (s *HTTPStaticServer) hUploadOrMkdir(w http.ResponseWriter, req *http.Reque
// Large file (>32MB) will store in tmp directory
// The quickest operation is call os.Move instead of os.Copy
// Note: it seems not working well, os.Rename might be failed
var copyErr error
if osFile, ok := file.(*os.File); ok && fileExists(osFile.Name()) {
tmpUploadPath := osFile.Name()
osFile.Close() // Windows can not rename opened file
log.Printf("Move %s -> %s", tmpUploadPath, dstPath)
copyErr = os.Rename(tmpUploadPath, dstPath)
} else {
dst, err := os.Create(dstPath)
if err != nil {
log.Println("Create file:", err)
http.Error(w, "File create "+err.Error(), http.StatusInternalServerError)
return
}
_, copyErr = io.Copy(dst, file)
dst.Close()
// if osFile, ok := file.(*os.File); ok && fileExists(osFile.Name()) {
// tmpUploadPath := osFile.Name()
// osFile.Close() // Windows can not rename opened file
// log.Printf("Move %s -> %s", tmpUploadPath, dstPath)
// copyErr = os.Rename(tmpUploadPath, dstPath)
// } else {
dst, err := os.Create(dstPath)
if err != nil {
log.Println("Create file:", err)
http.Error(w, "File create "+err.Error(), http.StatusInternalServerError)
return
}
// Note: very large size file might cause poor performance
// _, copyErr = io.Copy(dst, file)
buf := s.bufPool.Get().([]byte)
defer s.bufPool.Put(buf)
_, copyErr = io.CopyBuffer(dst, file, buf)
dst.Close()
// }
if copyErr != nil {
log.Println("Handle upload file:", err)
http.Error(w, err.Error(), http.StatusInternalServerError)