Fix serving of raw wiki files other than .md (#5814)
* 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>
This commit is contained in:
		
							parent
							
								
									4a747aef7b
								
							
						
					
					
						commit
						3b7f41f9f7
					
				|  | @ -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" |   revision = "dfcb80ca86e8534962c62812efd93209c7e600e7" | ||||||
|   version = "v1.2.4" |   version = "v1.3.2" | ||||||
| 
 | 
 | ||||||
| [[projects]] | [[projects]] | ||||||
|   digest = "1:00126f697efdcab42f07c89ac8bf0095fb2328aef6464e070055154088cea859" |   digest = "1:00126f697efdcab42f07c89ac8bf0095fb2328aef6464e070055154088cea859" | ||||||
|  |  | ||||||
|  | @ -0,0 +1,2 @@ | ||||||
|  | xŽŃmÄ DóMŰŔY¬Í<1A>˘(ůJ©`<60>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ę-%¸í’‡Űž<C5B0>ď	vÎ_Ą]ˇÔ^Ő/čI[t | ||||||
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | xÆM‚@†á¯MÛ àºré›°6ñœ&&&¬ü9LežÅ›w½Ý×åt<#ÞñÃÍ¡ªmv-·•0w¬b¦¢jyÌ–†¤Ú—~Ý‹[žæÉçý=HÄ÷.¾"à‚íµÄçÇ<>= | ||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,2 @@ | ||||||
|  | xŽÝmÃ0ƒû¬)n<>ú±t2íSèçÓÙ`ņ¥¶“e‚,VY¡/Hâ#È[)¹<>EûÒ@NÈq¦è툎Ñr2«)DöÅ0âŒj§C®ìÑLÂ<4C>ŸœaCÓÃ&š4B<34>v]$Eßí²ðIÓ‘e…¯¼þP×r¿I…sÍe“zªË³~_ | ||||||
|  | åõÄ[yã‡è¢v£<76>WíµV=í—›ü˘úH	vZ~s»@݉%Á•Ѝ?TÊZH | ||||||
										
											Binary file not shown.
										
									
								
							|  | @ -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) | 	if entry != nil { | ||||||
| 		return | 		if err = ServeBlob(ctx, entry.Blob()); err != nil { | ||||||
| 	} else if entry == nil { | 			ctx.ServerError("ServeBlob", err) | ||||||
| 		ctx.NotFound("findEntryForFile", nil) | 		} | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err = ServeBlob(ctx, entry.Blob()); err != nil { | 	ctx.NotFound("findEntryForFile", nil) | ||||||
| 		ctx.ServerError("ServeBlob", err) |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // 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 { | func NewResponseWriter(method string, rw http.ResponseWriter) ResponseWriter { | ||||||
| 	return &responseWriter{rw, 0, 0, nil} | 	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) | 	if rw.method != "HEAD" { | ||||||
| 	rw.size += size | 		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...) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue