Commit 80430a61 authored by Alessio Caiazza's avatar Alessio Caiazza

Merge branch 'sh-support-alt-document-root' into 'master'

Support alternate document root directory

See merge request gitlab-org/gitlab-workhorse!626
parents da81ec27 098d4474
testdata/data testdata/data
testdata/scratch testdata/scratch
testdata/public testdata/public
testdata/alt-public
/gitlab-workhorse /gitlab-workhorse
/gitlab-resize-image /gitlab-resize-image
/gitlab-zip-cat /gitlab-zip-cat
......
---
title: Support alternate document root directory
merge_request: 626
author:
type: added
# alt_document_root = '/home/git/public/assets'
[redis] [redis]
URL = "unix:/home/git/gitlab/redis/redis.socket" URL = "unix:/home/git/gitlab/redis/redis.socket"
......
...@@ -105,6 +105,7 @@ type Config struct { ...@@ -105,6 +105,7 @@ type Config struct {
ObjectStorageCredentials ObjectStorageCredentials `toml:"object_storage"` ObjectStorageCredentials ObjectStorageCredentials `toml:"object_storage"`
PropagateCorrelationID bool `toml:"-"` PropagateCorrelationID bool `toml:"-"`
ImageResizerConfig ImageResizerConfig `toml:"image_resizer"` ImageResizerConfig ImageResizerConfig `toml:"image_resizer"`
AltDocumentRoot string `toml:"alt_document_root"`
} }
var DefaultImageResizerConfig = ImageResizerConfig{ var DefaultImageResizerConfig = ImageResizerConfig{
......
...@@ -21,6 +21,7 @@ func TestLoadEmptyConfig(t *testing.T) { ...@@ -21,6 +21,7 @@ func TestLoadEmptyConfig(t *testing.T) {
cfg, err := LoadConfig(config) cfg, err := LoadConfig(config)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, cfg.AltDocumentRoot)
require.Equal(t, cfg.ImageResizerConfig.MaxFilesize, uint64(250000)) require.Equal(t, cfg.ImageResizerConfig.MaxFilesize, uint64(250000))
require.GreaterOrEqual(t, cfg.ImageResizerConfig.MaxScalerProcs, uint32(2)) require.GreaterOrEqual(t, cfg.ImageResizerConfig.MaxScalerProcs, uint32(2))
...@@ -97,3 +98,14 @@ max_filesize = 350000 ...@@ -97,3 +98,14 @@ max_filesize = 350000
require.Equal(t, expected, cfg.ImageResizerConfig) require.Equal(t, expected, cfg.ImageResizerConfig)
} }
func TestAltDocumentConfig(t *testing.T) {
config := `
alt_document_root = "/path/to/documents"
`
cfg, err := LoadConfig(config)
require.NoError(t, err)
require.Equal(t, "/path/to/documents", cfg.AltDocumentRoot)
}
...@@ -192,6 +192,16 @@ func (u *upstream) configureRoutes() { ...@@ -192,6 +192,16 @@ func (u *upstream) configureRoutes() {
proxy := buildProxy(u.Backend, u.Version, u.RoundTripper, u.Config) proxy := buildProxy(u.Backend, u.Version, u.RoundTripper, u.Config)
cableProxy := proxypkg.NewProxy(u.CableBackend, u.Version, u.CableRoundTripper) cableProxy := proxypkg.NewProxy(u.CableBackend, u.Version, u.CableRoundTripper)
assetsNotFoundHandler := NotFoundUnless(u.DevelopmentMode, proxy)
if u.AltDocumentRoot != "" {
altStatic := &staticpages.Static{DocumentRoot: u.AltDocumentRoot}
assetsNotFoundHandler = altStatic.ServeExisting(
u.URLPrefix,
staticpages.CacheExpireMax,
NotFoundUnless(u.DevelopmentMode, proxy),
)
}
signingTripper := secret.NewRoundTripper(u.RoundTripper, u.Version) signingTripper := secret.NewRoundTripper(u.RoundTripper, u.Version)
signingProxy := buildProxy(u.Backend, u.Version, signingTripper, u.Config) signingProxy := buildProxy(u.Backend, u.Version, signingTripper, u.Config)
...@@ -283,7 +293,7 @@ func (u *upstream) configureRoutes() { ...@@ -283,7 +293,7 @@ func (u *upstream) configureRoutes() {
static.ServeExisting( static.ServeExisting(
u.URLPrefix, u.URLPrefix,
staticpages.CacheExpireMax, staticpages.CacheExpireMax,
NotFoundUnless(u.DevelopmentMode, proxy), assetsNotFoundHandler,
), ),
withoutTracing(), // Tracing on assets is very noisy withoutTracing(), // Tracing on assets is very noisy
), ),
......
...@@ -143,6 +143,7 @@ func buildConfig(arg0 string, args []string) (*bootConfig, *config.Config, error ...@@ -143,6 +143,7 @@ func buildConfig(arg0 string, args []string) (*bootConfig, *config.Config, error
cfg.Redis = cfgFromFile.Redis cfg.Redis = cfgFromFile.Redis
cfg.ObjectStorageCredentials = cfgFromFile.ObjectStorageCredentials cfg.ObjectStorageCredentials = cfgFromFile.ObjectStorageCredentials
cfg.ImageResizerConfig = cfgFromFile.ImageResizerConfig cfg.ImageResizerConfig = cfgFromFile.ImageResizerConfig
cfg.AltDocumentRoot = cfgFromFile.AltDocumentRoot
return boot, cfg, nil return boot, cfg, nil
} }
......
...@@ -38,6 +38,7 @@ import ( ...@@ -38,6 +38,7 @@ import (
const scratchDir = "testdata/scratch" const scratchDir = "testdata/scratch"
const testRepoRoot = "testdata/data" const testRepoRoot = "testdata/data"
const testDocumentRoot = "testdata/public" const testDocumentRoot = "testdata/public"
const testAltDocumentRoot = "testdata/alt-public"
var absDocumentRoot string var absDocumentRoot string
...@@ -312,6 +313,72 @@ func TestGzipAssets(t *testing.T) { ...@@ -312,6 +313,72 @@ func TestGzipAssets(t *testing.T) {
} }
} }
func TestAltDocumentAssets(t *testing.T) {
path := "/assets/static.txt"
content := "asset"
require.NoError(t, setupAltStaticFile(path, content))
buf := &bytes.Buffer{}
gzipWriter := gzip.NewWriter(buf)
_, err := gzipWriter.Write([]byte(content))
require.NoError(t, err)
require.NoError(t, gzipWriter.Close())
contentGzip := buf.String()
require.NoError(t, setupAltStaticFile(path+".gz", contentGzip))
proxied := false
ts := testhelper.TestServerWithHandler(regexp.MustCompile(`.`), func(w http.ResponseWriter, r *http.Request) {
proxied = true
w.WriteHeader(404)
})
defer ts.Close()
upstreamConfig := newUpstreamConfig(ts.URL)
upstreamConfig.AltDocumentRoot = testAltDocumentRoot
ws := startWorkhorseServerWithConfig(upstreamConfig)
defer ws.Close()
testCases := []struct {
desc string
path string
content string
acceptEncoding string
contentEncoding string
}{
{desc: "plaintext asset", path: path, content: content},
{desc: "gzip asset available", path: path, content: contentGzip, acceptEncoding: "gzip", contentEncoding: "gzip"},
{desc: "non-existent file", path: "/assets/non-existent"},
}
for _, tc := range testCases {
req, err := http.NewRequest("GET", ws.URL+tc.path, nil)
require.NoError(t, err)
if tc.acceptEncoding != "" {
req.Header.Set("Accept-Encoding", tc.acceptEncoding)
}
resp, err := http.DefaultTransport.RoundTrip(req)
require.NoError(t, err)
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
if tc.content != "" {
require.Equal(t, 200, resp.StatusCode, "%s: status code", tc.desc)
require.Equal(t, tc.content, string(b), "%s: response body", tc.desc)
require.False(t, proxied, "%s: should not have made it to backend", tc.desc)
if tc.contentEncoding != "" {
require.Equal(t, tc.contentEncoding, resp.Header.Get("Content-Encoding"))
}
} else {
require.Equal(t, 404, resp.StatusCode, "%s: status code", tc.desc)
}
}
}
var sendDataHeader = "Gitlab-Workhorse-Send-Data" var sendDataHeader = "Gitlab-Workhorse-Send-Data"
func sendDataResponder(command string, literalJSON string) *httptest.Server { func sendDataResponder(command string, literalJSON string) *httptest.Server {
...@@ -576,11 +643,19 @@ func TestPropagateCorrelationIdHeader(t *testing.T) { ...@@ -576,11 +643,19 @@ func TestPropagateCorrelationIdHeader(t *testing.T) {
} }
func setupStaticFile(fpath, content string) error { func setupStaticFile(fpath, content string) error {
return setupStaticFileHelper(fpath, content, testDocumentRoot)
}
func setupAltStaticFile(fpath, content string) error {
return setupStaticFileHelper(fpath, content, testAltDocumentRoot)
}
func setupStaticFileHelper(fpath, content, directory string) error {
cwd, err := os.Getwd() cwd, err := os.Getwd()
if err != nil { if err != nil {
return err return err
} }
absDocumentRoot = path.Join(cwd, testDocumentRoot) absDocumentRoot = path.Join(cwd, directory)
if err := os.MkdirAll(path.Join(absDocumentRoot, path.Dir(fpath)), 0755); err != nil { if err := os.MkdirAll(path.Join(absDocumentRoot, path.Dir(fpath)), 0755); err != nil {
return err return err
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment