Browse Source

Added static router for file serving

master
Gisle Aune 7 years ago
parent
commit
ac6dddac38
  1. 4
      resource.go
  2. 8
      router.go
  3. 65
      static.go
  4. 66
      static_test.go

4
resource.go

@ -18,8 +18,8 @@ type Resource struct {
delete IDFunc
}
func NewResource(list, create Func, get, update, delete IDFunc) Resource {
return Resource{list, create, get, update, delete}
func NewResource(list, create Func, get, update, delete IDFunc) *Resource {
return &Resource{list, create, get, update, delete}
}
func (resource *Resource) Handle(path string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {

8
router.go

@ -73,6 +73,14 @@ func (router *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(404)
}
func (router *Router) Resource(mount string, list, create Func, get, update, delete IDFunc) {
router.Route(mount, NewResource(list, create, get, update, delete))
}
func (router *Router) Static(mount string, filePath string) {
router.Route(mount, NewStatic(filePath))
}
func (router *Router) Listen(host string, port int) error {
return http.ListenAndServe(fmt.Sprintf("%s:%d", host, port), router)
}

65
static.go

@ -0,0 +1,65 @@
package wrouter
import (
"io"
"mime"
"net/http"
"os"
"path"
"strings"
"git.aiterp.net/gisle/wrouter/response"
"git.aiterp.net/gisle/wrouter/auth"
)
type Static struct {
path string
}
func NewStatic(path string) *Static {
return &Static{path}
}
func (static *Static) Handle(urlPath string, w http.ResponseWriter, req *http.Request, user *auth.User) bool {
// Get the subpath out of the path
subpath := req.URL.Path[len(urlPath):]
if subpath[0] == '/' {
subpath = subpath[1:]
}
// Disallow breaking out of the folder
if strings.Contains(subpath, "..") {
response.Text(w, 403, "No .. in paths allowed")
return true
}
// Try loading the file
filepath := path.Join(static.path, subpath)
info, err := os.Stat(filepath)
if err != nil || info.IsDir() {
return false
}
file, err := os.Open(filepath)
if err != nil || file == nil {
return false
}
// Find and convert extension
ep := strings.LastIndex(filepath, ".")
ext := ""
if ep != -1 {
ext = filepath[ep:]
}
mimeType := mime.TypeByExtension(ext)
if mimeType == "" {
mimeType = "text/plain"
}
w.Header().Set("Content-Type", mimeType)
// Submit
w.WriteHeader(200)
io.Copy(w, file)
return true
}

66
static_test.go

@ -0,0 +1,66 @@
package wrouter
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestStatic(t *testing.T) {
router := &Router{}
router.Static("/data", "./")
server := httptest.NewServer(router)
t.Run("Download", func(t *testing.T) {
resp, err := http.Get(server.URL + "/data/README.md")
if err != nil {
t.Error("Request:", err)
t.Fail()
}
if resp.StatusCode != 200 {
t.Error("Expected 200, got", resp.Status)
t.Fail()
}
if resp.ContentLength == 0 {
t.Error("No content returned from server")
t.Fail()
}
if !strings.Contains(resp.Header.Get("Content-Type"), "text/plain") {
t.Errorf("Content-Type %s != %s", resp.Header.Get("Content-Type"), "text/plain")
t.Fail()
}
})
t.Run("Download_Fail", func(t *testing.T) {
resp, err := http.Get(server.URL + "/data/f42klfk2kf2kfk.md")
if err != nil {
t.Error("Request:", err)
t.Fail()
}
if resp.StatusCode != 404 {
t.Error("Expected 404, got", resp.Status)
t.Fail()
}
})
t.Run("Download_Fail2", func(t *testing.T) {
resp, err := http.Get(server.URL + "/data/../../../../../../../etc/passwd")
if err != nil {
t.Error("Request:", err)
t.Fail()
}
if resp.StatusCode != 403 {
t.Error("Expected 403, got", resp.Status)
t.Fail()
}
})
}
Loading…
Cancel
Save