Skip to content

Commit 19ae643

Browse files
lunnyzeripath
andauthored
Improve vfsgen to not unzip bindata files but send to browser directly (#7109)
* Don't unzip files from bindata but send to browser directly * remove dependent for httpgzip * Add tests for parseAcceptEncoding * Update docs for ENABLE_GZIP * Fix bug * Fix bug Co-authored-by: zeripath <[email protected]>
1 parent 87a0396 commit 19ae643

File tree

7 files changed

+105
-5
lines changed

7 files changed

+105
-5
lines changed

custom/conf/app.example.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ KEY_FILE = https/key.pem
361361
STATIC_ROOT_PATH =
362362
; Default path for App data
363363
APP_DATA_PATH = data
364-
; Application level GZIP support
364+
; Enable gzip compression for runtime-generated content, static resources excluded
365365
ENABLE_GZIP = false
366366
; Application profiling (memory and cpu)
367367
; For "web" command it listens on localhost:6060

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
264264
- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path.
265265
- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data.
266266
- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev".
267-
- `ENABLE_GZIP`: **false**: Enables application-level GZIP support.
267+
- `ENABLE_GZIP`: **false**: Enable gzip compression for runtime-generated content, static resources excluded.
268268
- `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on localhost:6060. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)_<username>_<temporary id>`
269269
- `PPROF_DATA_PATH`: **data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start gitea as service
270270
- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login\].

docs/content/doc/advanced/config-cheat-sheet.zh-cn.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ menu:
7070
- `KEY_FILE`: 启用HTTPS的密钥文件。
7171
- `STATIC_ROOT_PATH`: 存放模板和静态文件的根目录,默认是 Gitea 的根目录。
7272
- `STATIC_CACHE_TIME`: **6h**: 静态资源文件,包括 `custom/`, `public/` 和所有上传的头像的浏览器缓存时间。
73-
- `ENABLE_GZIP`: 启用应用级别的 GZIP 压缩。
73+
- `ENABLE_GZIP`: 启用实时生成的数据启用 GZIP 压缩,不包括静态资源
7474
- `LANDING_PAGE`: 未登录用户的默认页面,可选 `home``explore`
7575

7676
- `LFS_START_SERVER`: 是否启用 git-lfs 支持. 可以为 `true``false`, 默认是 `false`

modules/public/dynamic.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,19 @@
66

77
package public
88

9-
import "net/http"
9+
import (
10+
"io"
11+
"net/http"
12+
"os"
13+
"time"
14+
)
1015

1116
// Static implements the macaron static handler for serving assets.
1217
func Static(opts *Options) func(next http.Handler) http.Handler {
1318
return opts.staticHandler(opts.Directory)
1419
}
20+
21+
// ServeContent serve http content
22+
func ServeContent(w http.ResponseWriter, req *http.Request, fi os.FileInfo, modtime time.Time, content io.ReadSeeker) {
23+
http.ServeContent(w, req, fi.Name(), modtime, content)
24+
}

modules/public/public.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ func (opts *Options) staticHandler(dir string) func(next http.Handler) http.Hand
8787
}
8888
}
8989

90+
// parseAcceptEncoding parse Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5 as compress methods
91+
func parseAcceptEncoding(val string) map[string]bool {
92+
parts := strings.Split(val, ";")
93+
var types = make(map[string]bool)
94+
for _, v := range strings.Split(parts[0], ",") {
95+
types[strings.TrimSpace(v)] = true
96+
}
97+
return types
98+
}
99+
90100
func (opts *Options) handle(w http.ResponseWriter, req *http.Request, opt *Options) bool {
91101
if req.Method != "GET" && req.Method != "HEAD" {
92102
return false
@@ -157,6 +167,6 @@ func (opts *Options) handle(w http.ResponseWriter, req *http.Request, opt *Optio
157167
return true
158168
}
159169

160-
http.ServeContent(w, req, file, fi.ModTime(), f)
170+
ServeContent(w, req, fi, fi.ModTime(), f)
161171
return true
162172
}

modules/public/public_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package public
6+
7+
import (
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestParseAcceptEncoding(t *testing.T) {
14+
var kases = []struct {
15+
Header string
16+
Expected map[string]bool
17+
}{
18+
{
19+
Header: "deflate, gzip;q=1.0, *;q=0.5",
20+
Expected: map[string]bool{
21+
"deflate": true,
22+
"gzip": true,
23+
},
24+
},
25+
{
26+
Header: " gzip, deflate, br",
27+
Expected: map[string]bool{
28+
"deflate": true,
29+
"gzip": true,
30+
"br": true,
31+
},
32+
},
33+
}
34+
35+
for _, kase := range kases {
36+
t.Run(kase.Header, func(t *testing.T) {
37+
assert.EqualValues(t, kase.Expected, parseAcceptEncoding(kase.Header))
38+
})
39+
}
40+
}

modules/public/static.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@
77
package public
88

99
import (
10+
"bytes"
11+
"compress/gzip"
12+
"io"
1013
"io/ioutil"
14+
"mime"
1115
"net/http"
16+
"os"
17+
"path/filepath"
18+
"time"
19+
20+
"code.gitea.io/gitea/modules/log"
1221
)
1322

1423
// Static implements the macaron static handler for serving assets.
@@ -49,3 +58,34 @@ func AssetIsDir(name string) (bool, error) {
4958
}
5059
}
5160
}
61+
62+
// ServeContent serve http content
63+
func ServeContent(w http.ResponseWriter, req *http.Request, fi os.FileInfo, modtime time.Time, content io.ReadSeeker) {
64+
encodings := parseAcceptEncoding(req.Header.Get("Accept-Encoding"))
65+
if encodings["gzip"] {
66+
if cf, ok := fi.(*vfsgen۰CompressedFileInfo); ok {
67+
rd := bytes.NewReader(cf.GzipBytes())
68+
w.Header().Set("Content-Encoding", "gzip")
69+
ctype := mime.TypeByExtension(filepath.Ext(fi.Name()))
70+
if ctype == "" {
71+
// read a chunk to decide between utf-8 text and binary
72+
var buf [512]byte
73+
grd, _ := gzip.NewReader(rd)
74+
n, _ := io.ReadFull(grd, buf[:])
75+
ctype = http.DetectContentType(buf[:n])
76+
_, err := rd.Seek(0, io.SeekStart) // rewind to output whole file
77+
if err != nil {
78+
log.Error("rd.Seek error: %v", err)
79+
http.Error(w, http.StatusText(500), 500)
80+
return
81+
}
82+
}
83+
w.Header().Set("Content-Type", ctype)
84+
http.ServeContent(w, req, fi.Name(), modtime, rd)
85+
return
86+
}
87+
}
88+
89+
http.ServeContent(w, req, fi.Name(), modtime, content)
90+
return
91+
}

0 commit comments

Comments
 (0)