* Fix serving of raw wiki files other than .md Closes #4690. Closes #4395. Signed-off-by: Gabriel Silva Simões <simoes.sgabriel@gmail.com> * Simplify code at routers/repo/wiki.go Signed-off-by: Gabriel Silva Simões <simoes.sgabriel@gmail.com> * Add more files to user2/repo1.wiki for testing Signed-off-by: Gabriel Silva Simões <simoes.sgabriel@gmail.com> * Update macaron to v1.3.2 Signed-off-by: Gabriel Silva Simões <simoes.sgabriel@gmail.com> * Add tests for WikiRaw Signed-off-by: Gabriel Silva Simões <simoes.sgabriel@gmail.com> * Fix NewResponseWriter usage due to macaron update Signed-off-by: Gabriel Silva Simões <simoes.sgabriel@gmail.com> * Add raw to reserved wiki names Signed-off-by: Gabriel Silva Simões <simoes.sgabriel@gmail.com>tags/v1.21.12.1
| @@ -1108,12 +1108,12 @@ | |||||
| version = "v2.5.1" | version = "v2.5.1" | ||||
| [[projects]] | [[projects]] | ||||
| digest = "1:cfe1730a152ff033ad7d9c115d22e36b19eec6d5928c06146b9119be45d39dc0" | |||||
| digest = "1:de2e7294c9bd0b7d07ada8e98ad02cbbaabacff90eedebe7454ebdbab50d0d19" | |||||
| name = "gopkg.in/macaron.v1" | name = "gopkg.in/macaron.v1" | ||||
| packages = ["."] | packages = ["."] | ||||
| pruneopts = "NUT" | pruneopts = "NUT" | ||||
| revision = "75f2e9b42e99652f0d82b28ccb73648f44615faa" | |||||
| version = "v1.2.4" | |||||
| revision = "dfcb80ca86e8534962c62812efd93209c7e600e7" | |||||
| version = "v1.3.2" | |||||
| [[projects]] | [[projects]] | ||||
| digest = "1:00126f697efdcab42f07c89ac8bf0095fb2328aef6464e070055154088cea859" | digest = "1:00126f697efdcab42f07c89ac8bf0095fb2328aef6464e070055154088cea859" | ||||
| @@ -0,0 +1,2 @@ | |||||
| xŽŃmÄ DóMŰŔY¬Í�˘(ůJ©`�5ÇÉś-›K*Ki,Hi!?ŁŃ<éiâVki0Z˙ÔXH“D(Z6ĨGňSb» 3“JDŢhµó!÷uB¬ĚDaJpˇ íśŮčFôLĆą4+~´ëvŔ;‡ŁČ | |||||
| eýäžőç[Nx>KÝäÎü‡_sĺ˛q«/€]09MHpѤµękżÜä_dę-%¸í’‡Űž�ď vÎ_Ą]ˇÔ^Ő/čI[t | |||||
| @@ -0,0 +1 @@ | |||||
| xÆM‚@†á¯MÛ àºré›°6ñœ&&&¬ü9LežÅ›w½Ý×åt<#ÞñÃÍ¡ªmv-·•0w¬b¦¢jyÌ–†¤Ú—~Ý‹[žæÉçý=HÄ÷.¾"à‚íµÄçÇ�= | |||||
| @@ -0,0 +1,2 @@ | |||||
| xŽÝmÃ0ƒû¬)n�ú±t2íSèçÓÙ`ņ¥¶“e‚,VY¡/Hâ#È[)¹�EûÒ@NÈq¦è툎Ñr2«)DöÅ0âŒj§C®ìÑLÂ�ŸœaCÓÃ&š4B�v]$Eßí²ðIÓ‘e…¯¼þP×r¿I…sÍe“zªË³~_ | |||||
| åõÄ[yã‡è¢v£�WíµV=í—›ü˘úH vZ~s»@݉%Á•Ѝ?TÊZH | |||||
| @@ -1 +1 @@ | |||||
| 2c54faec6c45d31c1abfaecdab471eac6633738a | |||||
| 0cf15c3f66ec8384480ed9c3cf87c9e97fbb0ec3 | |||||
| @@ -22,7 +22,7 @@ import ( | |||||
| ) | ) | ||||
| var ( | var ( | ||||
| reservedWikiNames = []string{"_pages", "_new", "_edit"} | |||||
| reservedWikiNames = []string{"_pages", "_new", "_edit", "raw"} | |||||
| wikiWorkingPool = sync.NewExclusivePool() | wikiWorkingPool = sync.NewExclusivePool() | ||||
| ) | ) | ||||
| @@ -27,7 +27,7 @@ func createContext(req *http.Request) (*macaron.Context, *httptest.ResponseRecor | |||||
| c := &macaron.Context{ | c := &macaron.Context{ | ||||
| Injector: inject.New(), | Injector: inject.New(), | ||||
| Req: macaron.Request{Request: req}, | Req: macaron.Request{Request: req}, | ||||
| Resp: macaron.NewResponseWriter(resp), | |||||
| Resp: macaron.NewResponseWriter(req.Method, resp), | |||||
| Render: &macaron.DummyRender{ResponseWriter: resp}, | Render: &macaron.DummyRender{ResponseWriter: resp}, | ||||
| Data: make(map[string]interface{}), | Data: make(map[string]interface{}), | ||||
| } | } | ||||
| @@ -295,26 +295,41 @@ func WikiRaw(ctx *context.Context) { | |||||
| return | return | ||||
| } | } | ||||
| } | } | ||||
| providedPath := ctx.Params("*") | providedPath := ctx.Params("*") | ||||
| if strings.HasSuffix(providedPath, ".md") { | |||||
| providedPath = providedPath[:len(providedPath)-3] | |||||
| } | |||||
| wikiPath := models.WikiNameToFilename(providedPath) | |||||
| var entry *git.TreeEntry | var entry *git.TreeEntry | ||||
| if commit != nil { | if commit != nil { | ||||
| entry, err = findEntryForFile(commit, wikiPath) | |||||
| // Try to find a file with that name | |||||
| entry, err = findEntryForFile(commit, providedPath) | |||||
| if err != nil { | |||||
| ctx.ServerError("findFile", err) | |||||
| return | |||||
| } | |||||
| if entry == nil { | |||||
| // Try to find a wiki page with that name | |||||
| if strings.HasSuffix(providedPath, ".md") { | |||||
| providedPath = providedPath[:len(providedPath)-3] | |||||
| } | |||||
| wikiPath := models.WikiNameToFilename(providedPath) | |||||
| entry, err = findEntryForFile(commit, wikiPath) | |||||
| if err != nil { | |||||
| ctx.ServerError("findFile", err) | |||||
| return | |||||
| } | |||||
| } | |||||
| } | } | ||||
| if err != nil { | |||||
| ctx.ServerError("findFile", err) | |||||
| return | |||||
| } else if entry == nil { | |||||
| ctx.NotFound("findEntryForFile", nil) | |||||
| if entry != nil { | |||||
| if err = ServeBlob(ctx, entry.Blob()); err != nil { | |||||
| ctx.ServerError("ServeBlob", err) | |||||
| } | |||||
| return | return | ||||
| } | } | ||||
| if err = ServeBlob(ctx, entry.Blob()); err != nil { | |||||
| ctx.ServerError("ServeBlob", err) | |||||
| } | |||||
| ctx.NotFound("findEntryForFile", nil) | |||||
| } | } | ||||
| // NewWiki render wiki create page | // NewWiki render wiki create page | ||||
| @@ -77,7 +77,7 @@ func TestWiki(t *testing.T) { | |||||
| Wiki(ctx) | Wiki(ctx) | ||||
| assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | ||||
| assert.EqualValues(t, "Home", ctx.Data["Title"]) | assert.EqualValues(t, "Home", ctx.Data["Title"]) | ||||
| assertPagesMetas(t, []string{"Home"}, ctx.Data["Pages"]) | |||||
| assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name"}, ctx.Data["Pages"]) | |||||
| } | } | ||||
| func TestWikiPages(t *testing.T) { | func TestWikiPages(t *testing.T) { | ||||
| @@ -87,7 +87,7 @@ func TestWikiPages(t *testing.T) { | |||||
| test.LoadRepo(t, ctx, 1) | test.LoadRepo(t, ctx, 1) | ||||
| WikiPages(ctx) | WikiPages(ctx) | ||||
| assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | ||||
| assertPagesMetas(t, []string{"Home"}, ctx.Data["Pages"]) | |||||
| assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name"}, ctx.Data["Pages"]) | |||||
| } | } | ||||
| func TestNewWiki(t *testing.T) { | func TestNewWiki(t *testing.T) { | ||||
| @@ -185,3 +185,23 @@ func TestDeleteWikiPagePost(t *testing.T) { | |||||
| assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | ||||
| assertWikiNotExists(t, ctx.Repo.Repository, "Home") | assertWikiNotExists(t, ctx.Repo.Repository, "Home") | ||||
| } | } | ||||
| func TestWikiRaw(t *testing.T) { | |||||
| for filepath, filetype := range map[string]string{ | |||||
| "jpeg.jpg": "image/jpeg", | |||||
| "Page With Spaced Name": "text/plain; charset=utf-8", | |||||
| "Page-With-Spaced-Name": "text/plain; charset=utf-8", | |||||
| "Page With Spaced Name.md": "text/plain; charset=utf-8", | |||||
| "Page-With-Spaced-Name.md": "text/plain; charset=utf-8", | |||||
| } { | |||||
| models.PrepareTestEnv(t) | |||||
| ctx := test.MockContext(t, "user2/repo1/wiki/raw/"+filepath) | |||||
| ctx.SetParams("*", filepath) | |||||
| test.LoadUser(t, ctx, 2) | |||||
| test.LoadRepo(t, ctx, 1) | |||||
| WikiRaw(ctx) | |||||
| assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) | |||||
| assert.EqualValues(t, filetype, ctx.Resp.Header().Get("Content-Type")) | |||||
| } | |||||
| } | |||||
| @@ -262,7 +262,7 @@ func (ctx *Context) Params(name string) string { | |||||
| // SetParams sets value of param with given name. | // SetParams sets value of param with given name. | ||||
| func (ctx *Context) SetParams(name, val string) { | func (ctx *Context) SetParams(name, val string) { | ||||
| if !strings.HasPrefix(name, ":") { | |||||
| if name != "*" && !strings.HasPrefix(name, ":") { | |||||
| name = ":" + name | name = ":" + name | ||||
| } | } | ||||
| ctx.params[name] = val | ctx.params[name] = val | ||||
| @@ -270,7 +270,7 @@ func (ctx *Context) SetParams(name, val string) { | |||||
| // ReplaceAllParams replace all current params with given params | // ReplaceAllParams replace all current params with given params | ||||
| func (ctx *Context) ReplaceAllParams(params Params) { | func (ctx *Context) ReplaceAllParams(params Params) { | ||||
| ctx.params = params; | |||||
| ctx.params = params | |||||
| } | } | ||||
| // ParamsEscape returns escapred params result. | // ParamsEscape returns escapred params result. | ||||
| @@ -32,7 +32,7 @@ import ( | |||||
| "github.com/go-macaron/inject" | "github.com/go-macaron/inject" | ||||
| ) | ) | ||||
| const _VERSION = "1.2.4.1123" | |||||
| const _VERSION = "1.3.2.1216" | |||||
| func Version() string { | func Version() string { | ||||
| return _VERSION | return _VERSION | ||||
| @@ -194,7 +194,7 @@ func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Cont | |||||
| index: 0, | index: 0, | ||||
| Router: m.Router, | Router: m.Router, | ||||
| Req: Request{req}, | Req: Request{req}, | ||||
| Resp: NewResponseWriter(rw), | |||||
| Resp: NewResponseWriter(req.Method, rw), | |||||
| Render: &DummyRender{rw}, | Render: &DummyRender{rw}, | ||||
| Data: make(map[string]interface{}), | Data: make(map[string]interface{}), | ||||
| } | } | ||||
| @@ -42,11 +42,12 @@ type ResponseWriter interface { | |||||
| type BeforeFunc func(ResponseWriter) | type BeforeFunc func(ResponseWriter) | ||||
| // NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter | // NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter | ||||
| func NewResponseWriter(rw http.ResponseWriter) ResponseWriter { | |||||
| return &responseWriter{rw, 0, 0, nil} | |||||
| func NewResponseWriter(method string, rw http.ResponseWriter) ResponseWriter { | |||||
| return &responseWriter{method, rw, 0, 0, nil} | |||||
| } | } | ||||
| type responseWriter struct { | type responseWriter struct { | ||||
| method string | |||||
| http.ResponseWriter | http.ResponseWriter | ||||
| status int | status int | ||||
| size int | size int | ||||
| @@ -59,13 +60,15 @@ func (rw *responseWriter) WriteHeader(s int) { | |||||
| rw.status = s | rw.status = s | ||||
| } | } | ||||
| func (rw *responseWriter) Write(b []byte) (int, error) { | |||||
| func (rw *responseWriter) Write(b []byte) (size int, err error) { | |||||
| if !rw.Written() { | if !rw.Written() { | ||||
| // The status will be StatusOK if WriteHeader has not been called yet | // The status will be StatusOK if WriteHeader has not been called yet | ||||
| rw.WriteHeader(http.StatusOK) | rw.WriteHeader(http.StatusOK) | ||||
| } | } | ||||
| size, err := rw.ResponseWriter.Write(b) | |||||
| rw.size += size | |||||
| if rw.method != "HEAD" { | |||||
| size, err = rw.ResponseWriter.Write(b) | |||||
| rw.size += size | |||||
| } | |||||
| return size, err | return size, err | ||||
| } | } | ||||
| @@ -96,7 +96,7 @@ func NewRouter() *Router { | |||||
| } | } | ||||
| // SetAutoHead sets the value who determines whether add HEAD method automatically | // SetAutoHead sets the value who determines whether add HEAD method automatically | ||||
| // when GET method is added. Combo router will not be affected by this value. | |||||
| // when GET method is added. | |||||
| func (r *Router) SetAutoHead(v bool) { | func (r *Router) SetAutoHead(v bool) { | ||||
| r.autoHead = v | r.autoHead = v | ||||
| } | } | ||||
| @@ -341,6 +341,9 @@ func (cr *ComboRouter) route(fn func(string, ...Handler) *Route, method string, | |||||
| } | } | ||||
| func (cr *ComboRouter) Get(h ...Handler) *ComboRouter { | func (cr *ComboRouter) Get(h ...Handler) *ComboRouter { | ||||
| if cr.router.autoHead { | |||||
| cr.Head(h...) | |||||
| } | |||||
| return cr.route(cr.router.Get, "GET", h...) | return cr.route(cr.router.Get, "GET", h...) | ||||
| } | } | ||||