Gisle Aune
8 years ago
4 changed files with 141 additions and 2 deletions
-
4resource.go
-
8router.go
-
65static.go
-
66static_test.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 |
|||
} |
@ -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() |
|||
} |
|||
}) |
|||
} |
Reference in new issue
xxxxxxxxxx