2021-02-22 17:27:13 +05:30
|
|
|
package staticpages
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"compress/gzip"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
"gitlab.com/gitlab-org/gitlab/workhorse/internal/testhelper"
|
2021-02-22 17:27:13 +05:30
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestServingNonExistingFile(t *testing.T) {
|
|
|
|
dir := "/path/to/non/existing/directory"
|
|
|
|
httpRequest, _ := http.NewRequest("GET", "/file", nil)
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
2021-03-05 16:19:46 +05:30
|
|
|
st := &Static{DocumentRoot: dir}
|
2021-02-22 17:27:13 +05:30
|
|
|
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
|
|
|
|
require.Equal(t, 404, w.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestServingDirectory(t *testing.T) {
|
2022-07-23 23:45:48 +05:30
|
|
|
dir := t.TempDir()
|
2021-02-22 17:27:13 +05:30
|
|
|
|
|
|
|
httpRequest, _ := http.NewRequest("GET", "/file", nil)
|
|
|
|
w := httptest.NewRecorder()
|
2021-03-05 16:19:46 +05:30
|
|
|
st := &Static{DocumentRoot: dir}
|
2021-02-22 17:27:13 +05:30
|
|
|
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
|
|
|
|
require.Equal(t, 404, w.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestServingMalformedUri(t *testing.T) {
|
|
|
|
dir := "/path/to/non/existing/directory"
|
|
|
|
httpRequest, _ := http.NewRequest("GET", "/../../../static/file", nil)
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
2021-03-05 16:19:46 +05:30
|
|
|
st := &Static{DocumentRoot: dir}
|
2021-02-22 17:27:13 +05:30
|
|
|
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
|
|
|
|
require.Equal(t, 404, w.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExecutingHandlerWhenNoFileFound(t *testing.T) {
|
|
|
|
dir := "/path/to/non/existing/directory"
|
|
|
|
httpRequest, _ := http.NewRequest("GET", "/file", nil)
|
|
|
|
|
|
|
|
executed := false
|
2021-03-05 16:19:46 +05:30
|
|
|
st := &Static{DocumentRoot: dir}
|
2021-02-22 17:27:13 +05:30
|
|
|
st.ServeExisting("/", CacheDisabled, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
|
|
|
|
executed = (r == httpRequest)
|
|
|
|
})).ServeHTTP(nil, httpRequest)
|
|
|
|
if !executed {
|
|
|
|
t.Error("The handler should get executed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestServingTheActualFile(t *testing.T) {
|
2022-07-23 23:45:48 +05:30
|
|
|
dir := t.TempDir()
|
2021-02-22 17:27:13 +05:30
|
|
|
|
|
|
|
httpRequest, _ := http.NewRequest("GET", "/file", nil)
|
|
|
|
|
|
|
|
fileContent := "STATIC"
|
2022-07-23 23:45:48 +05:30
|
|
|
os.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600)
|
2021-02-22 17:27:13 +05:30
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
2021-03-05 16:19:46 +05:30
|
|
|
st := &Static{DocumentRoot: dir}
|
2021-02-22 17:27:13 +05:30
|
|
|
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
|
2022-05-07 20:08:51 +05:30
|
|
|
testhelper.RequireResponseHeader(t, w, "X-Content-Type-Options", "nosniff")
|
2021-02-22 17:27:13 +05:30
|
|
|
require.Equal(t, 200, w.Code)
|
|
|
|
if w.Body.String() != fileContent {
|
|
|
|
t.Error("We should serve the file: ", w.Body.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-05 16:19:46 +05:30
|
|
|
func TestExcludedPaths(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
path string
|
|
|
|
found bool
|
|
|
|
contents string
|
|
|
|
}{
|
|
|
|
{"allowed file", "/file1", true, "contents1"},
|
|
|
|
{"path traversal is allowed", "/uploads/../file1", true, "contents1"},
|
|
|
|
{"files in /uploads/ are invisible", "/uploads/file2", false, ""},
|
|
|
|
{"cannot use path traversal to get to /uploads/", "/foobar/../uploads/file2", false, ""},
|
|
|
|
{"cannot use escaped path traversal to get to /uploads/", "/foobar%2f%2e%2e%2fuploads/file2", false, ""},
|
|
|
|
{"cannot use double escaped path traversal to get to /uploads/", "/foobar%252f%252e%252e%252fuploads/file2", false, ""},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
|
|
httpRequest, err := http.NewRequest("GET", tc.path, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
|
|
|
st := &Static{DocumentRoot: "testdata", Exclude: []string{"/uploads/"}}
|
|
|
|
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
|
|
|
|
|
|
|
|
if tc.found {
|
2022-05-07 20:08:51 +05:30
|
|
|
testhelper.RequireResponseHeader(t, w, "X-Content-Type-Options", "nosniff")
|
2021-03-05 16:19:46 +05:30
|
|
|
require.Equal(t, 200, w.Code)
|
|
|
|
require.Equal(t, tc.contents, w.Body.String())
|
|
|
|
} else {
|
|
|
|
require.Equal(t, 404, w.Code)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-22 17:27:13 +05:30
|
|
|
func testServingThePregzippedFile(t *testing.T, enableGzip bool) {
|
2022-07-23 23:45:48 +05:30
|
|
|
dir := t.TempDir()
|
2021-02-22 17:27:13 +05:30
|
|
|
|
|
|
|
httpRequest, _ := http.NewRequest("GET", "/file", nil)
|
|
|
|
|
|
|
|
if enableGzip {
|
|
|
|
httpRequest.Header.Set("Accept-Encoding", "gzip, deflate")
|
|
|
|
}
|
|
|
|
|
|
|
|
fileContent := "STATIC"
|
|
|
|
|
|
|
|
var fileGzipContent bytes.Buffer
|
|
|
|
fileGzip := gzip.NewWriter(&fileGzipContent)
|
|
|
|
fileGzip.Write([]byte(fileContent))
|
|
|
|
fileGzip.Close()
|
|
|
|
|
2022-07-23 23:45:48 +05:30
|
|
|
os.WriteFile(filepath.Join(dir, "file.gz"), fileGzipContent.Bytes(), 0600)
|
|
|
|
os.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600)
|
2021-02-22 17:27:13 +05:30
|
|
|
|
|
|
|
w := httptest.NewRecorder()
|
2021-03-05 16:19:46 +05:30
|
|
|
st := &Static{DocumentRoot: dir}
|
2021-02-22 17:27:13 +05:30
|
|
|
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
|
2022-05-07 20:08:51 +05:30
|
|
|
testhelper.RequireResponseHeader(t, w, "X-Content-Type-Options", "nosniff")
|
2021-02-22 17:27:13 +05:30
|
|
|
require.Equal(t, 200, w.Code)
|
|
|
|
if enableGzip {
|
|
|
|
testhelper.RequireResponseHeader(t, w, "Content-Encoding", "gzip")
|
|
|
|
if !bytes.Equal(w.Body.Bytes(), fileGzipContent.Bytes()) {
|
|
|
|
t.Error("We should serve the pregzipped file")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
require.Equal(t, 200, w.Code)
|
|
|
|
testhelper.RequireResponseHeader(t, w, "Content-Encoding")
|
|
|
|
if w.Body.String() != fileContent {
|
|
|
|
t.Error("We should serve the file: ", w.Body.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestServingThePregzippedFile(t *testing.T) {
|
|
|
|
testServingThePregzippedFile(t, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestServingThePregzippedFileWithoutEncoding(t *testing.T) {
|
|
|
|
testServingThePregzippedFile(t, false)
|
|
|
|
}
|