mirror of
https://github.com/Forceu/Gokapi.git
synced 2026-03-13 13:39:02 -05:00
Fixed CleanUp deleting file that was actively downloaded, which then failed the download, fixed write timeout, made webserver unit tests parallel, serve correct content header.
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
cd ..
|
||||
go test ./... -coverprofile=/tmp/coverage.out --tags=test && go tool cover -html=/tmp/coverage.out
|
||||
go test ./... -parallel 8 -coverprofile=/tmp/coverage.out --tags=test && go tool cover -html=/tmp/coverage.out
|
||||
|
||||
@@ -34,26 +34,27 @@ var Environment environment.Environment
|
||||
var ServerSettings Configuration
|
||||
|
||||
// Version of the configuration structure. Used for upgrading
|
||||
const currentConfigVersion = 4
|
||||
const currentConfigVersion = 5
|
||||
|
||||
// Configuration is a struct that contains the global configuration
|
||||
type Configuration struct {
|
||||
Port string `json:"Port"`
|
||||
AdminName string `json:"AdminName"`
|
||||
AdminPassword string `json:"AdminPassword"`
|
||||
ServerUrl string `json:"ServerUrl"`
|
||||
DefaultDownloads int `json:"DefaultDownloads"`
|
||||
DefaultExpiry int `json:"DefaultExpiry"`
|
||||
DefaultPassword string `json:"DefaultPassword"`
|
||||
RedirectUrl string `json:"RedirectUrl"`
|
||||
Sessions map[string]sessionstructure.Session `json:"Sessions"`
|
||||
Files map[string]filestructure.File `json:"Files"`
|
||||
Hotlinks map[string]filestructure.Hotlink `json:"Hotlinks"`
|
||||
ConfigVersion int `json:"ConfigVersion"`
|
||||
SaltAdmin string `json:"SaltAdmin"`
|
||||
SaltFiles string `json:"SaltFiles"`
|
||||
LengthId int `json:"LengthId"`
|
||||
DataDir string `json:"DataDir"`
|
||||
Port string `json:"Port"`
|
||||
AdminName string `json:"AdminName"`
|
||||
AdminPassword string `json:"AdminPassword"`
|
||||
ServerUrl string `json:"ServerUrl"`
|
||||
DefaultDownloads int `json:"DefaultDownloads"`
|
||||
DefaultExpiry int `json:"DefaultExpiry"`
|
||||
DefaultPassword string `json:"DefaultPassword"`
|
||||
RedirectUrl string `json:"RedirectUrl"`
|
||||
Sessions map[string]sessionstructure.Session `json:"Sessions"`
|
||||
Files map[string]filestructure.File `json:"Files"`
|
||||
Hotlinks map[string]filestructure.Hotlink `json:"Hotlinks"`
|
||||
DownloadStatus map[string]filestructure.DownloadStatus `json:"DownloadStatus"`
|
||||
ConfigVersion int `json:"ConfigVersion"`
|
||||
SaltAdmin string `json:"SaltAdmin"`
|
||||
SaltFiles string `json:"SaltFiles"`
|
||||
LengthId int `json:"LengthId"`
|
||||
DataDir string `json:"DataDir"`
|
||||
}
|
||||
|
||||
// Load loads the configuration or creates the folder structure and a default configuration
|
||||
@@ -92,6 +93,16 @@ func updateConfig() {
|
||||
ServerSettings.Hotlinks = make(map[string]filestructure.Hotlink)
|
||||
}
|
||||
|
||||
// < v1.1.4
|
||||
if ServerSettings.ConfigVersion < 5 {
|
||||
ServerSettings.LengthId = 15
|
||||
ServerSettings.DownloadStatus = make(map[string]filestructure.DownloadStatus)
|
||||
for _, file := range ServerSettings.Files {
|
||||
file.ContentType = "application/octet-stream"
|
||||
ServerSettings.Files[file.Id] = file
|
||||
}
|
||||
}
|
||||
|
||||
if ServerSettings.ConfigVersion < currentConfigVersion {
|
||||
fmt.Println("Successfully upgraded database")
|
||||
ServerSettings.ConfigVersion = currentConfigVersion
|
||||
|
||||
52
internal/configuration/downloadStatus/DownloadStatus.go
Normal file
52
internal/configuration/downloadStatus/DownloadStatus.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package downloadStatus
|
||||
|
||||
import (
|
||||
"Gokapi/internal/configuration"
|
||||
"Gokapi/internal/helper"
|
||||
"Gokapi/internal/storage/filestructure"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SetDownload creates a new DownloadStatus struct and returns its Id
|
||||
func SetDownload(file filestructure.File) string {
|
||||
status := newDownloadStatus(file)
|
||||
configuration.ServerSettings.DownloadStatus[status.Id] = status
|
||||
return status.Id
|
||||
}
|
||||
|
||||
// SetComplete removes the download object
|
||||
func SetComplete(id string) {
|
||||
delete(configuration.ServerSettings.DownloadStatus, id)
|
||||
}
|
||||
|
||||
// Clean removes all expires status objects
|
||||
func Clean() {
|
||||
now := time.Now().Unix()
|
||||
for _, item := range configuration.ServerSettings.DownloadStatus {
|
||||
if item.ExpireAt < now {
|
||||
delete(configuration.ServerSettings.DownloadStatus, item.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// newDownloadStatus initialises the a new DownloadStatus item
|
||||
func newDownloadStatus(file filestructure.File) filestructure.DownloadStatus {
|
||||
s := filestructure.DownloadStatus{
|
||||
Id: helper.GenerateRandomString(30),
|
||||
FileId: file.Id,
|
||||
ExpireAt: time.Now().Add(24 * time.Hour).Unix(),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// IsCurrentlyDownloading returns true if file is currently being downloaded
|
||||
func IsCurrentlyDownloading(file filestructure.File) bool {
|
||||
for _, status := range configuration.ServerSettings.DownloadStatus {
|
||||
if status.FileId == file.Id {
|
||||
if status.ExpireAt > time.Now().Unix() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
70
internal/configuration/downloadStatus/DownloadStatus_test.go
Normal file
70
internal/configuration/downloadStatus/DownloadStatus_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package downloadStatus
|
||||
|
||||
import (
|
||||
"Gokapi/internal/configuration"
|
||||
"Gokapi/internal/storage/filestructure"
|
||||
"Gokapi/pkg/test"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var testFile filestructure.File
|
||||
var statusId string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
configuration.ServerSettings.DownloadStatus = make(map[string]filestructure.DownloadStatus)
|
||||
testFile = filestructure.File{
|
||||
Id: "test",
|
||||
Name: "testName",
|
||||
Size: "3 B",
|
||||
SHA256: "123456",
|
||||
ExpireAt: 500,
|
||||
ExpireAtString: "expire",
|
||||
DownloadsRemaining: 1,
|
||||
}
|
||||
exitVal := m.Run()
|
||||
os.Exit(exitVal)
|
||||
}
|
||||
|
||||
func TestNewDownloadStatus(t *testing.T) {
|
||||
status := newDownloadStatus(filestructure.File{Id: "testId"})
|
||||
test.IsNotEmpty(t, status.Id)
|
||||
test.IsEqualString(t, status.FileId, "testId")
|
||||
test.IsEqualBool(t, status.ExpireAt > time.Now().Unix(), true)
|
||||
}
|
||||
|
||||
func TestSetDownload(t *testing.T) {
|
||||
statusId = SetDownload(testFile)
|
||||
status := configuration.ServerSettings.DownloadStatus[statusId]
|
||||
test.IsNotEmpty(t, status.Id)
|
||||
test.IsEqualString(t, status.Id, statusId)
|
||||
test.IsEqualString(t, status.FileId, testFile.Id)
|
||||
test.IsEqualBool(t, status.ExpireAt > time.Now().Unix(), true)
|
||||
}
|
||||
|
||||
func TestSetComplete(t *testing.T) {
|
||||
status := configuration.ServerSettings.DownloadStatus[statusId]
|
||||
test.IsNotEmpty(t, status.Id)
|
||||
SetComplete(statusId)
|
||||
status = configuration.ServerSettings.DownloadStatus[statusId]
|
||||
test.IsEmpty(t, status.Id)
|
||||
}
|
||||
|
||||
func TestIsCurrentlyDownloading(t *testing.T) {
|
||||
statusId = SetDownload(testFile)
|
||||
test.IsEqualBool(t, IsCurrentlyDownloading(testFile), true)
|
||||
test.IsEqualBool(t, IsCurrentlyDownloading(filestructure.File{Id: "notDownloading"}), false)
|
||||
}
|
||||
|
||||
func TestClean(t *testing.T) {
|
||||
test.IsEqualInt(t, len(configuration.ServerSettings.DownloadStatus), 1)
|
||||
Clean()
|
||||
test.IsEqualInt(t, len(configuration.ServerSettings.DownloadStatus), 1)
|
||||
status := configuration.ServerSettings.DownloadStatus[statusId]
|
||||
status.ExpireAt = 1
|
||||
configuration.ServerSettings.DownloadStatus[statusId] = status
|
||||
test.IsEqualInt(t, len(configuration.ServerSettings.DownloadStatus), 1)
|
||||
Clean()
|
||||
test.IsEqualInt(t, len(configuration.ServerSettings.DownloadStatus), 0)
|
||||
}
|
||||
@@ -6,12 +6,12 @@ Serving and processing uploaded files
|
||||
|
||||
import (
|
||||
"Gokapi/internal/configuration"
|
||||
"Gokapi/internal/configuration/downloadStatus"
|
||||
"Gokapi/internal/helper"
|
||||
"Gokapi/internal/storage/filestructure"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
@@ -47,6 +47,7 @@ func processUpload(fileContent *[]byte, fileHeader *multipart.FileHeader, expire
|
||||
ExpireAtString: time.Unix(expireAt, 0).Format("2006-01-02 15:04"),
|
||||
DownloadsRemaining: downloads,
|
||||
PasswordHash: configuration.HashPassword(password, true),
|
||||
ContentType: fileHeader.Header.Get("Content-Type"),
|
||||
}
|
||||
addHotlink(&file)
|
||||
configuration.ServerSettings.Files[id] = file
|
||||
@@ -111,33 +112,33 @@ func GetFileByHotlink(id string) (filestructure.File, bool) {
|
||||
func ServeFile(file filestructure.File, w http.ResponseWriter, r *http.Request, forceDownload bool) {
|
||||
file.DownloadsRemaining = file.DownloadsRemaining - 1
|
||||
configuration.ServerSettings.Files[file.Id] = file
|
||||
// Investigate: Possible race condition with clean-up routine?
|
||||
configuration.Save()
|
||||
|
||||
if forceDownload {
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=\""+file.Name+"\"")
|
||||
}
|
||||
w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
|
||||
storageData, err := os.OpenFile(configuration.ServerSettings.DataDir+"/"+file.SHA256, os.O_RDONLY, 0644)
|
||||
helper.Check(err)
|
||||
defer storageData.Close()
|
||||
size, err := helper.GetFileSize(storageData)
|
||||
if err == nil {
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
|
||||
}
|
||||
helper.Check(err)
|
||||
_, _ = io.Copy(w, storageData)
|
||||
if forceDownload {
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=\""+file.Name+"\"")
|
||||
}
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
|
||||
w.Header().Set("Content-Type", file.ContentType)
|
||||
statusId := downloadStatus.SetDownload(file)
|
||||
configuration.Save()
|
||||
http.ServeContent(w, r, file.Name, time.Now(), storageData)
|
||||
downloadStatus.SetComplete(statusId)
|
||||
configuration.Save()
|
||||
}
|
||||
|
||||
// CleanUp removes expired files from the config and from the filesystem if they are not referenced by other files anymore
|
||||
// Will be called periodically or after a file has been manually deleted in the admin view.
|
||||
// If parameter periodic is true, this function is recursive and calls itself every hour.
|
||||
func CleanUp(periodic bool) {
|
||||
downloadStatus.Clean()
|
||||
timeNow := time.Now().Unix()
|
||||
wasItemDeleted := false
|
||||
for key, element := range configuration.ServerSettings.Files {
|
||||
fileExists := helper.FileExists(configuration.ServerSettings.DataDir + "/" + element.SHA256)
|
||||
if element.ExpireAt < timeNow || element.DownloadsRemaining < 1 || !fileExists {
|
||||
if (element.ExpireAt < timeNow || element.DownloadsRemaining < 1 || !fileExists) && !downloadStatus.IsCurrentlyDownloading(element) {
|
||||
deleteFile := true
|
||||
for _, secondLoopElement := range configuration.ServerSettings.Files {
|
||||
if element.Id != secondLoopElement.Id && element.SHA256 == secondLoopElement.SHA256 {
|
||||
|
||||
@@ -100,6 +100,7 @@ func TestServeFile(t *testing.T) {
|
||||
|
||||
test.IsEqualString(t, w.Result().Header.Get("Content-Disposition"), "attachment; filename=\"test.dat\"")
|
||||
test.IsEqualString(t, w.Result().Header.Get("Content-Length"), "35")
|
||||
test.IsEqualString(t, w.Result().Header.Get("Content-Type"), "text")
|
||||
content, err := ioutil.ReadAll(w.Result().Body)
|
||||
test.IsNil(t, err)
|
||||
test.IsEqualString(t, string(content), "This is a file for testing purposes")
|
||||
@@ -107,13 +108,17 @@ func TestServeFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCleanUp(t *testing.T) {
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["cleanuptest123456789"].Name, "cleanup")
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["Wzol7LyY2QVczXynJtVo"].Name, "smallfile2")
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["e4TjE7CokWK0giiLNxDL"].Name, "smallfile2")
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["wefffewhtrhhtrhtrhtr"].Name, "smallfile3")
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["n1tSTAGj8zan9KaT4u6p"].Name, "picture.jpg")
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["deletedfile123456789"].Name, "DeletedFile")
|
||||
test.IsEqualBool(t, helper.FileExists("test/data/2341354656543213246465465465432456898794"), true)
|
||||
|
||||
CleanUp(false)
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["cleanuptest123456789"].Name, "cleanup")
|
||||
test.IsEqualBool(t, helper.FileExists("test/data/2341354656543213246465465465432456898794"), true)
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["deletedfile123456789"].Name, "")
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["Wzol7LyY2QVczXynJtVo"].Name, "smallfile2")
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["e4TjE7CokWK0giiLNxDL"].Name, "smallfile2")
|
||||
@@ -159,4 +164,10 @@ func TestCleanUp(t *testing.T) {
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["e4TjE7CokWK0giiLNxDL"].Name, "")
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["wefffewhtrhhtrhtrhtr"].Name, "")
|
||||
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["cleanuptest123456789"].Name, "cleanup")
|
||||
test.IsEqualBool(t, helper.FileExists("test/data/2341354656543213246465465465432456898794"), true)
|
||||
configuration.ServerSettings.DownloadStatus = make(map[string]filestructure.DownloadStatus)
|
||||
CleanUp(false)
|
||||
test.IsEqualString(t, configuration.ServerSettings.Files["cleanuptest123456789"].Name, "")
|
||||
test.IsEqualBool(t, helper.FileExists("test/data/2341354656543213246465465465432456898794"), false)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ type File struct {
|
||||
DownloadsRemaining int `json:"DownloadsRemaining"`
|
||||
PasswordHash string `json:"PasswordHash"`
|
||||
HotlinkId string `json:"HotlinkId"`
|
||||
ContentType string `json:"ContentType"`
|
||||
}
|
||||
|
||||
// Hotlink is a struct containing hotlink ids
|
||||
@@ -47,3 +48,11 @@ type Result struct {
|
||||
Url string `json:"Url"`
|
||||
HotlinkUrl string `json:"HotlinkUrl"`
|
||||
}
|
||||
|
||||
|
||||
// DownloadStatus contains current downloads, so they do not get removed during cleanup
|
||||
type DownloadStatus struct {
|
||||
Id string
|
||||
FileId string
|
||||
ExpireAt int64
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ func TestToJsonResult(t *testing.T) {
|
||||
DownloadsRemaining: 1,
|
||||
PasswordHash: "pwhash",
|
||||
HotlinkId: "hotlinkid",
|
||||
ContentType: "test/html",
|
||||
}
|
||||
test.IsEqualString(t, file.ToJsonResult("serverurl/"), `{"Result":"OK","FileInfo":{"Id":"testId","Name":"testName","Size":"10 B","SHA256":"sha256","ExpireAt":50,"ExpireAtString":"future","DownloadsRemaining":1,"PasswordHash":"pwhash","HotlinkId":"hotlinkid"},"Url":"serverurl/d?id=","HotlinkUrl":"serverurl/hotlink/"}`)
|
||||
test.IsEqualString(t, file.ToJsonResult("serverurl/"), `{"Result":"OK","FileInfo":{"Id":"testId","Name":"testName","Size":"10 B","SHA256":"sha256","ExpireAt":50,"ExpireAtString":"future","DownloadsRemaining":1,"PasswordHash":"pwhash","HotlinkId":"hotlinkid","ContentType":"test/html"},"Url":"serverurl/d?id=","HotlinkUrl":"serverurl/hotlink/"}`)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ func Create(initFiles bool) {
|
||||
os.WriteFile("test/data/a8fdc205a9f19cc1c7507a60c4f01b13d11d7fd0", []byte("123"), 0777)
|
||||
os.WriteFile("test/data/c4f9375f9834b4e7f0a528cc65c055702bf5f24a", []byte("456"), 0777)
|
||||
os.WriteFile("test/data/e017693e4a04a59d0b0f400fe98177fe7ee13cf7", []byte("789"), 0777)
|
||||
os.WriteFile("test/data/2341354656543213246465465465432456898794", []byte("abc"), 0777)
|
||||
os.WriteFile("test/fileupload.jpg", []byte("abc"), 0777)
|
||||
}
|
||||
}
|
||||
@@ -64,6 +65,10 @@ var configTestFile = []byte(`{
|
||||
"RenewAt":2147483645,
|
||||
"ValidUntil":2147483646
|
||||
},
|
||||
"logoutsession":{
|
||||
"RenewAt":2147483645,
|
||||
"ValidUntil":2147483646
|
||||
},
|
||||
"needsRenewal":{
|
||||
"RenewAt":0,
|
||||
"ValidUntil":2147483646
|
||||
@@ -83,6 +88,7 @@ var configTestFile = []byte(`{
|
||||
"ExpireAtString":"2021-05-04 15:19",
|
||||
"DownloadsRemaining":1,
|
||||
"PasswordHash":"",
|
||||
"ContentType":"text/html",
|
||||
"HotlinkId":""
|
||||
},
|
||||
"e4TjE7CokWK0giiLNxDL":{
|
||||
@@ -94,6 +100,7 @@ var configTestFile = []byte(`{
|
||||
"ExpireAtString":"2021-05-04 15:19",
|
||||
"DownloadsRemaining":2,
|
||||
"PasswordHash":"",
|
||||
"ContentType":"text/html",
|
||||
"HotlinkId":""
|
||||
},
|
||||
"wefffewhtrhhtrhtrhtr":{
|
||||
@@ -105,6 +112,7 @@ var configTestFile = []byte(`{
|
||||
"ExpireAtString":"2021-05-04 15:19",
|
||||
"DownloadsRemaining":1,
|
||||
"PasswordHash":"",
|
||||
"ContentType":"text/html",
|
||||
"HotlinkId":""
|
||||
},
|
||||
"deletedfile123456789":{
|
||||
@@ -116,6 +124,7 @@ var configTestFile = []byte(`{
|
||||
"ExpireAtString":"2021-05-04 15:19",
|
||||
"DownloadsRemaining":2,
|
||||
"PasswordHash":"",
|
||||
"ContentType":"text/html",
|
||||
"HotlinkId":""
|
||||
},
|
||||
"jpLXGJKigM4hjtA6T6sN":{
|
||||
@@ -126,6 +135,19 @@ var configTestFile = []byte(`{
|
||||
"ExpireAt":2147483646,
|
||||
"ExpireAtString":"2021-05-04 15:18",
|
||||
"DownloadsRemaining":1,
|
||||
"ContentType":"text/html",
|
||||
"PasswordHash":"7b30508aa9b233ab4b8a11b2af5816bdb58ca3e7",
|
||||
"HotlinkId":""
|
||||
},
|
||||
"jpLXGJKigM4hjtA6T6sN2":{
|
||||
"Id":"jpLXGJKigM4hjtA6T6sN2",
|
||||
"Name":"smallfile",
|
||||
"Size":"7 B",
|
||||
"SHA256":"c4f9375f9834b4e7f0a528cc65c055702bf5f24a",
|
||||
"ExpireAt":2147483646,
|
||||
"ExpireAtString":"2021-05-04 15:18",
|
||||
"DownloadsRemaining":1,
|
||||
"ContentType":"text/html",
|
||||
"PasswordHash":"7b30508aa9b233ab4b8a11b2af5816bdb58ca3e7",
|
||||
"HotlinkId":""
|
||||
},
|
||||
@@ -138,7 +160,20 @@ var configTestFile = []byte(`{
|
||||
"ExpireAtString":"2021-05-04 15:19",
|
||||
"DownloadsRemaining":1,
|
||||
"PasswordHash":"",
|
||||
"ContentType":"text/html",
|
||||
"HotlinkId":"PhSs6mFtf8O5YGlLMfNw9rYXx9XRNkzCnJZpQBi7inunv3Z4A.jpg"
|
||||
},
|
||||
"cleanuptest123456789":{
|
||||
"Id":"cleanuptest123456789",
|
||||
"Name":"cleanup",
|
||||
"Size":"4 B",
|
||||
"SHA256":"2341354656543213246465465465432456898794",
|
||||
"ExpireAt":2147483646,
|
||||
"ExpireAtString":"2021-05-04 15:19",
|
||||
"DownloadsRemaining":0,
|
||||
"PasswordHash":"",
|
||||
"ContentType":"text/html",
|
||||
"HotlinkId":""
|
||||
}
|
||||
},
|
||||
"Hotlinks":{
|
||||
@@ -147,7 +182,14 @@ var configTestFile = []byte(`{
|
||||
"FileId":"n1tSTAGj8zan9KaT4u6p"
|
||||
}
|
||||
},
|
||||
"ConfigVersion":4,
|
||||
"DownloadStatus":{
|
||||
"69JCbLVxx2KxfvB6FYkrDn3oCU7BWT":{
|
||||
"Id":"69JCbLVxx2KxfvB6FYkrDn3oCU7BWT",
|
||||
"FileId":"cleanuptest123456789",
|
||||
"ExpireAt":2147483646
|
||||
}
|
||||
},
|
||||
"ConfigVersion":5,
|
||||
"SaltAdmin":"LW6fW4Pjv8GtdWVLSZD66gYEev6NAaXxOVBw7C",
|
||||
"SaltFiles":"lL5wMTtnVCn5TPbpRaSe4vAQodWW0hgk00WCZE",
|
||||
"LengthId":20,
|
||||
|
||||
@@ -34,7 +34,7 @@ var staticFolderEmbedded embed.FS
|
||||
//go:embed web/templates
|
||||
var templateFolderEmbedded embed.FS
|
||||
|
||||
const timeOutWebserver = 2 * time.Hour
|
||||
const timeOutWebserver = 12 * time.Hour
|
||||
|
||||
// Variable containing all parsed templates
|
||||
var templateFolder *template.Template
|
||||
@@ -74,7 +74,7 @@ func Start() {
|
||||
srv := &http.Server{
|
||||
Addr: configuration.ServerSettings.Port,
|
||||
ReadTimeout: timeOutWebserver,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
WriteTimeout: timeOutWebserver,
|
||||
}
|
||||
log.Fatal(srv.ListenAndServe())
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ import (
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testconfiguration.Create(true)
|
||||
configuration.Load()
|
||||
go Start()
|
||||
time.Sleep(1 * time.Second)
|
||||
exitVal := m.Run()
|
||||
testconfiguration.Delete()
|
||||
os.Exit(exitVal)
|
||||
@@ -33,64 +36,75 @@ func TestEmbedFs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebserverEmbedFs(t *testing.T) {
|
||||
configuration.Load()
|
||||
go Start()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
// Index redirect
|
||||
func TestIndexRedirect(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/",
|
||||
RequiredContent: "<html><head><meta http-equiv=\"Refresh\" content=\"0; URL=./index\"></head></html>",
|
||||
RequiredContent: []string{"<html><head><meta http-equiv=\"Refresh\" content=\"0; URL=./index\"></head></html>"},
|
||||
IsHtml: true,
|
||||
})
|
||||
// Index file
|
||||
}
|
||||
func TestIndexFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/index",
|
||||
RequiredContent: configuration.ServerSettings.RedirectUrl,
|
||||
RequiredContent: []string{configuration.ServerSettings.RedirectUrl},
|
||||
IsHtml: true,
|
||||
})
|
||||
// CSS file
|
||||
}
|
||||
func TestStaticDirs(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/css/cover.css",
|
||||
RequiredContent: ".btn-secondary:hover",
|
||||
RequiredContent: []string{".btn-secondary:hover"},
|
||||
})
|
||||
// Login page
|
||||
}
|
||||
func TestLogin(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/login",
|
||||
RequiredContent: "id=\"uname_hidden\"",
|
||||
RequiredContent: []string{"id=\"uname_hidden\""},
|
||||
IsHtml: true,
|
||||
})
|
||||
// Admin without auth
|
||||
}
|
||||
func TestAdminNoAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: "URL=./login\"",
|
||||
RequiredContent: []string{"URL=./login\""},
|
||||
IsHtml: true,
|
||||
})
|
||||
// Admin with auth
|
||||
}
|
||||
func TestAdminAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: "Downloads remaining",
|
||||
RequiredContent: []string{"Downloads remaining"},
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "validsession",
|
||||
}},
|
||||
})
|
||||
// Admin with expired session
|
||||
}
|
||||
func TestAdminExpiredAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: "URL=./login\"",
|
||||
RequiredContent: []string{"URL=./login\""},
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "expiredsession",
|
||||
}},
|
||||
})
|
||||
// Admin with auth needing renewal
|
||||
}
|
||||
|
||||
func TestAdminRenewalAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
cookies := test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: "Downloads remaining",
|
||||
RequiredContent: []string{"Downloads remaining"},
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
@@ -109,124 +123,209 @@ func TestWebserverEmbedFs(t *testing.T) {
|
||||
}
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: "Downloads remaining",
|
||||
RequiredContent: []string{"Downloads remaining"},
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: sessionCookie,
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
// Admin with invalid auth
|
||||
func TestAdminInvalidAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: "URL=./login\"",
|
||||
RequiredContent: []string{"URL=./login\""},
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "invalid",
|
||||
}},
|
||||
})
|
||||
// Invalid link
|
||||
}
|
||||
|
||||
func TestInvalidLink(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/d?id=123",
|
||||
RequiredContent: "URL=./error\"",
|
||||
RequiredContent: []string{"URL=./error\""},
|
||||
IsHtml: true,
|
||||
})
|
||||
// Error
|
||||
}
|
||||
func TestError(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/error",
|
||||
RequiredContent: "this file cannot be found",
|
||||
RequiredContent: []string{"this file cannot be found"},
|
||||
IsHtml: true,
|
||||
})
|
||||
// Forgot pw
|
||||
}
|
||||
func TestForgotPw(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/forgotpw",
|
||||
RequiredContent: "--reset-pw",
|
||||
RequiredContent: []string{"--reset-pw"},
|
||||
IsHtml: true,
|
||||
})
|
||||
// Login correct
|
||||
}
|
||||
func TestLoginCorrect(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/login",
|
||||
RequiredContent: "URL=./admin\"",
|
||||
RequiredContent: []string{"URL=./admin\""},
|
||||
IsHtml: true,
|
||||
Method: "POST",
|
||||
PostValues: []test.PostBody{{"username", "test"}, {"password", "testtest"}},
|
||||
})
|
||||
// Login incorrect
|
||||
}
|
||||
|
||||
func TestLoginIncorrectPassword(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/login",
|
||||
RequiredContent: "Incorrect username or password",
|
||||
RequiredContent: []string{"Incorrect username or password"},
|
||||
IsHtml: true,
|
||||
Method: "POST",
|
||||
PostValues: []test.PostBody{{"username", "test"}, {"password", "incorrect"}},
|
||||
})
|
||||
// Login incorrect
|
||||
}
|
||||
func TestLoginIncorrectUsername(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/login",
|
||||
RequiredContent: "Incorrect username or password",
|
||||
RequiredContent: []string{"Incorrect username or password"},
|
||||
IsHtml: true,
|
||||
Method: "POST",
|
||||
PostValues: []test.PostBody{{"username", "incorrect"}, {"password", "incorrect"}},
|
||||
})
|
||||
// Download hotlink
|
||||
}
|
||||
|
||||
func TestLogout(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: []string{"Downloads remaining"},
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "logoutsession",
|
||||
}},
|
||||
})
|
||||
// Logout
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/logout",
|
||||
RequiredContent: []string{"URL=./login\""},
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "logoutsession",
|
||||
}},
|
||||
})
|
||||
// Admin after logout
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: []string{"URL=./login\""},
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "logoutsession",
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func TestDownloadHotlink(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/hotlink/PhSs6mFtf8O5YGlLMfNw9rYXx9XRNkzCnJZpQBi7inunv3Z4A.jpg",
|
||||
RequiredContent: "123",
|
||||
RequiredContent: []string{"123"},
|
||||
})
|
||||
// Download expired hotlink
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/hotlink/PhSs6mFtf8O5YGlLMfNw9rYXx9XRNkzCnJZpQBi7inunv3Z4A.jpg",
|
||||
RequiredContent: "Created with GIMP",
|
||||
RequiredContent: []string{"Created with GIMP"},
|
||||
})
|
||||
// Show download page no password
|
||||
}
|
||||
|
||||
func TestDownloadNoPassword(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Show download page
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/d?id=Wzol7LyY2QVczXynJtVo",
|
||||
IsHtml: true,
|
||||
RequiredContent: "smallfile2",
|
||||
RequiredContent: []string{"smallfile2"},
|
||||
})
|
||||
// Download file no password
|
||||
// Download
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/downloadFile?id=Wzol7LyY2QVczXynJtVo",
|
||||
RequiredContent: "789",
|
||||
RequiredContent: []string{"789"},
|
||||
})
|
||||
// Show download page expired file
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/d?id=Wzol7LyY2QVczXynJtVo",
|
||||
IsHtml: true,
|
||||
RequiredContent: "URL=./error\"",
|
||||
RequiredContent: []string{"URL=./error\""},
|
||||
})
|
||||
// Download expired file
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/downloadFile?id=Wzol7LyY2QVczXynJtVo",
|
||||
IsHtml: true,
|
||||
RequiredContent: "URL=./error\"",
|
||||
RequiredContent: []string{"URL=./error\""},
|
||||
})
|
||||
// Show download page password
|
||||
}
|
||||
|
||||
func TestDownloadPagePassword(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/d?id=jpLXGJKigM4hjtA6T6sN",
|
||||
IsHtml: true,
|
||||
RequiredContent: "Password required",
|
||||
RequiredContent: []string{"Password required"},
|
||||
})
|
||||
// Show download page incorrect password
|
||||
}
|
||||
func TestDownloadPageIncorrectPassword(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/d?id=jpLXGJKigM4hjtA6T6sN",
|
||||
IsHtml: true,
|
||||
RequiredContent: "Incorrect password!",
|
||||
RequiredContent: []string{"Incorrect password!"},
|
||||
Method: "POST",
|
||||
PostValues: []test.PostBody{{"password", "incorrect"}},
|
||||
})
|
||||
// Submit download page correct password
|
||||
cookies = test.HttpPageResult(t, test.HttpTestConfig{
|
||||
}
|
||||
|
||||
func TestDownloadIncorrectPasswordCookie(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/d?id=jpLXGJKigM4hjtA6T6sN",
|
||||
IsHtml: true,
|
||||
RequiredContent: "URL=./d?id=jpLXGJKigM4hjtA6T6sN",
|
||||
RequiredContent: []string{"Password required"},
|
||||
Cookies: []test.Cookie{{"pjpLXGJKigM4hjtA6T6sN", "invalid"}},
|
||||
})
|
||||
}
|
||||
|
||||
func TestDownloadIncorrectPassword(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/downloadFile?id=jpLXGJKigM4hjtA6T6sN",
|
||||
IsHtml: true,
|
||||
RequiredContent: []string{"URL=./d?id=jpLXGJKigM4hjtA6T6sN"},
|
||||
Cookies: []test.Cookie{{"pjpLXGJKigM4hjtA6T6sN", "invalid"}},
|
||||
})
|
||||
}
|
||||
|
||||
func TestDownloadCorrectPassword(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Submit download page correct password
|
||||
cookies := test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/d?id=jpLXGJKigM4hjtA6T6sN2",
|
||||
IsHtml: true,
|
||||
RequiredContent: []string{"URL=./d?id=jpLXGJKigM4hjtA6T6sN2"},
|
||||
Method: "POST",
|
||||
PostValues: []test.PostBody{{"password", "123"}},
|
||||
})
|
||||
pwCookie := ""
|
||||
for _, cookie := range cookies {
|
||||
if (*cookie).Name == "pjpLXGJKigM4hjtA6T6sN" {
|
||||
if (*cookie).Name == "pjpLXGJKigM4hjtA6T6sN2" {
|
||||
pwCookie = (*cookie).Value
|
||||
break
|
||||
}
|
||||
@@ -236,79 +335,79 @@ func TestWebserverEmbedFs(t *testing.T) {
|
||||
}
|
||||
// Show download page correct password
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/d?id=jpLXGJKigM4hjtA6T6sN",
|
||||
Url: "http://127.0.0.1:53843/d?id=jpLXGJKigM4hjtA6T6sN2",
|
||||
IsHtml: true,
|
||||
RequiredContent: "smallfile",
|
||||
Cookies: []test.Cookie{{"pjpLXGJKigM4hjtA6T6sN", pwCookie}},
|
||||
})
|
||||
// Show download page incorrect password cookie
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/d?id=jpLXGJKigM4hjtA6T6sN",
|
||||
IsHtml: true,
|
||||
RequiredContent: "Password required",
|
||||
Cookies: []test.Cookie{{"pjpLXGJKigM4hjtA6T6sN", "invalid"}},
|
||||
})
|
||||
// Download incorrect password
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/downloadFile?id=jpLXGJKigM4hjtA6T6sN",
|
||||
IsHtml: true,
|
||||
RequiredContent: "URL=./d?id=jpLXGJKigM4hjtA6T6sN",
|
||||
Cookies: []test.Cookie{{"pjpLXGJKigM4hjtA6T6sN", "invalid"}},
|
||||
RequiredContent: []string{"smallfile"},
|
||||
Cookies: []test.Cookie{{"pjpLXGJKigM4hjtA6T6sN2", pwCookie}},
|
||||
})
|
||||
// Download correct password
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/downloadFile?id=jpLXGJKigM4hjtA6T6sN",
|
||||
RequiredContent: "456",
|
||||
Cookies: []test.Cookie{{"pjpLXGJKigM4hjtA6T6sN", pwCookie}},
|
||||
Url: "http://127.0.0.1:53843/downloadFile?id=jpLXGJKigM4hjtA6T6sN2",
|
||||
RequiredContent: []string{"456"},
|
||||
Cookies: []test.Cookie{{"pjpLXGJKigM4hjtA6T6sN2", pwCookie}},
|
||||
})
|
||||
// Delete file non-auth
|
||||
}
|
||||
|
||||
func TestDeleteFileNonAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/delete?id=e4TjE7CokWK0giiLNxDL",
|
||||
IsHtml: true,
|
||||
RequiredContent: "URL=./login",
|
||||
RequiredContent: []string{"URL=./login"},
|
||||
})
|
||||
// Delete file authorised
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/delete?id=e4TjE7CokWK0giiLNxDL",
|
||||
IsHtml: true,
|
||||
RequiredContent: "URL=./admin",
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "validsession",
|
||||
}},
|
||||
})
|
||||
// Delete file authorised, invalid key
|
||||
}
|
||||
|
||||
func TestDeleteFileInvalidKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/delete",
|
||||
IsHtml: true,
|
||||
RequiredContent: "URL=./admin",
|
||||
RequiredContent: []string{"URL=./admin"},
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "validsession",
|
||||
}},
|
||||
})
|
||||
// Post upload unauthorized
|
||||
test.HttpPostRequest(t, "http://127.0.0.1:53843/upload", "test/fileupload.jpg", "file", "{\"Result\":\"error\",\"ErrorMessage\":\"Not authenticated\"}", []test.Cookie{})
|
||||
// Post upload authorized
|
||||
test.HttpPostRequest(t, "http://127.0.0.1:53843/upload", "test/fileupload.jpg", "file", "fileupload.jpg", []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "validsession",
|
||||
}})
|
||||
// Logout
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/logout",
|
||||
RequiredContent: "URL=./login\"",
|
||||
IsHtml: true,
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "validsession",
|
||||
}},
|
||||
})
|
||||
// Admin after logout
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://localhost:53843/admin",
|
||||
RequiredContent: "URL=./login\"",
|
||||
Url: "http://127.0.0.1:53843/delete?id=",
|
||||
IsHtml: true,
|
||||
RequiredContent: []string{"URL=./admin"},
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "validsession",
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPageResult(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/delete?id=e4TjE7CokWK0giiLNxDL",
|
||||
IsHtml: true,
|
||||
RequiredContent: []string{"URL=./admin"},
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "validsession",
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostUploadNoAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
test.HttpPostRequest(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/upload",
|
||||
UploadFileName: "test/fileupload.jpg",
|
||||
UploadFieldName: "file",
|
||||
RequiredContent: []string{"{\"Result\":\"error\",\"ErrorMessage\":\"Not authenticated\"}"},
|
||||
})
|
||||
}
|
||||
func TestPostUpload(t *testing.T) {
|
||||
test.HttpPostRequest(t, test.HttpTestConfig{
|
||||
Url: "http://127.0.0.1:53843/upload",
|
||||
UploadFileName: "test/fileupload.jpg",
|
||||
UploadFieldName: "file",
|
||||
RequiredContent: []string{"{\"Result\":\"OK\"", "\"Name\":\"fileupload.jpg\"", "\"SHA256\":\"a9993e364706816aba3e25717850c26c9cd0d89d\"", "DownloadsRemaining\":3"},
|
||||
ExcludedContent: []string{"\"Id\":\"\"", "HotlinkId\":\"\""},
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
Value: "validsession",
|
||||
|
||||
@@ -36,6 +36,20 @@ func IsEqualInt(t *testing.T, got, want int) {
|
||||
}
|
||||
}
|
||||
|
||||
// IsNotEmpty fails test if string is empty
|
||||
func IsNotEmpty(t *testing.T, s string) {
|
||||
if s == "" {
|
||||
t.Errorf("Assertion failed, got: %s, want: empty.", s)
|
||||
}
|
||||
}
|
||||
|
||||
// IsEmpty fails test if string is not empty
|
||||
func IsEmpty(t *testing.T, s string) {
|
||||
if s != "" {
|
||||
t.Errorf("Assertion failed, got: %s, want: empty.", s)
|
||||
}
|
||||
}
|
||||
|
||||
// IsNil fails test if error not nil
|
||||
func IsNil(t *testing.T, got error) {
|
||||
if got != nil {
|
||||
@@ -44,22 +58,22 @@ func IsNil(t *testing.T, got error) {
|
||||
}
|
||||
|
||||
// HttpPageResult tests if a http server is outputting the correct result
|
||||
func HttpPageResult(t *testing.T, configuration HttpTestConfig) []*http.Cookie {
|
||||
configuration.init()
|
||||
func HttpPageResult(t *testing.T, config HttpTestConfig) []*http.Cookie {
|
||||
config.init()
|
||||
client := &http.Client{}
|
||||
|
||||
data := url.Values{}
|
||||
for _, value := range configuration.PostValues {
|
||||
for _, value := range config.PostValues {
|
||||
data.Add(value.Key, value.Value)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(configuration.Method, configuration.Url, strings.NewReader(data.Encode()))
|
||||
req, err := http.NewRequest(config.Method, config.Url, strings.NewReader(data.Encode()))
|
||||
IsNil(t, err)
|
||||
|
||||
for _, cookie := range configuration.Cookies {
|
||||
for _, cookie := range config.Cookies {
|
||||
req.Header.Set("Cookie", cookie.toString())
|
||||
}
|
||||
if len(configuration.PostValues) > 0 {
|
||||
if len(config.PostValues) > 0 {
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))
|
||||
}
|
||||
@@ -69,13 +83,20 @@ func HttpPageResult(t *testing.T, configuration HttpTestConfig) []*http.Cookie {
|
||||
if resp.StatusCode != 200 {
|
||||
t.Errorf("Status %d != 200", resp.StatusCode)
|
||||
}
|
||||
bs, err := ioutil.ReadAll(resp.Body)
|
||||
content, err := ioutil.ReadAll(resp.Body)
|
||||
IsNil(t, err)
|
||||
if configuration.IsHtml && !bytes.Contains(bs, []byte("</html>")) {
|
||||
t.Error(configuration.Url + ": Incorrect response")
|
||||
if config.IsHtml && !bytes.Contains(content, []byte("</html>")) {
|
||||
t.Error(config.Url + ": Incorrect response")
|
||||
}
|
||||
if configuration.RequiredContent != "" && !bytes.Contains(bs, []byte(configuration.RequiredContent)) {
|
||||
t.Error(configuration.Url + ": Incorrect response. Got:\n" + string(bs))
|
||||
for _, requiredString := range config.RequiredContent {
|
||||
if !bytes.Contains(content, []byte(requiredString)) {
|
||||
t.Error(config.Url + ": Incorrect response. Got:\n" + string(content))
|
||||
}
|
||||
}
|
||||
for _, excludedString := range config.ExcludedContent {
|
||||
if bytes.Contains(content, []byte(excludedString)) {
|
||||
t.Error(config.Url + ": Incorrect response. Got:\n" + string(content))
|
||||
}
|
||||
}
|
||||
resp.Body.Close()
|
||||
return resp.Cookies()
|
||||
@@ -84,11 +105,14 @@ func HttpPageResult(t *testing.T, configuration HttpTestConfig) []*http.Cookie {
|
||||
// HttpTestConfig is a struct for http test init
|
||||
type HttpTestConfig struct {
|
||||
Url string
|
||||
RequiredContent string
|
||||
RequiredContent []string
|
||||
ExcludedContent []string
|
||||
IsHtml bool
|
||||
Method string
|
||||
PostValues []PostBody
|
||||
Cookies []Cookie
|
||||
UploadFileName string
|
||||
UploadFieldName string
|
||||
}
|
||||
|
||||
func (c *HttpTestConfig) init() {
|
||||
@@ -117,21 +141,21 @@ type PostBody struct {
|
||||
}
|
||||
|
||||
// HttpPostRequest sends a post request
|
||||
func HttpPostRequest(t *testing.T, url, filename, fieldName, requiredText string, cookies []Cookie) {
|
||||
file, err := os.Open(filename)
|
||||
func HttpPostRequest(t *testing.T, config HttpTestConfig) {
|
||||
file, err := os.Open(config.UploadFileName)
|
||||
IsNil(t, err)
|
||||
defer file.Close()
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
part, err := writer.CreateFormFile(fieldName, filepath.Base(file.Name()))
|
||||
part, err := writer.CreateFormFile(config.UploadFieldName, filepath.Base(file.Name()))
|
||||
IsNil(t, err)
|
||||
|
||||
io.Copy(part, file)
|
||||
writer.Close()
|
||||
request, err := http.NewRequest("POST", url, body)
|
||||
request, err := http.NewRequest("POST", config.Url, body)
|
||||
IsNil(t, err)
|
||||
|
||||
for _, cookie := range cookies {
|
||||
for _, cookie := range config.Cookies {
|
||||
request.Header.Set("Cookie", cookie.toString())
|
||||
}
|
||||
request.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
@@ -144,7 +168,14 @@ func HttpPostRequest(t *testing.T, url, filename, fieldName, requiredText string
|
||||
content, err := ioutil.ReadAll(response.Body)
|
||||
IsNil(t, err)
|
||||
|
||||
if requiredText != "" && !bytes.Contains(content, []byte(requiredText)) {
|
||||
t.Error(url + ": Incorrect response. Got:\n" + string(content))
|
||||
for _, requiredString := range config.RequiredContent {
|
||||
if !bytes.Contains(content, []byte(requiredString)) {
|
||||
t.Error(config.Url + ": Incorrect response. Got:\n" + string(content))
|
||||
}
|
||||
}
|
||||
for _, excludedString := range config.ExcludedContent {
|
||||
if bytes.Contains(content, []byte(excludedString)) {
|
||||
t.Error(config.Url + ": Incorrect response. Got:\n" + string(content))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user