From ec5b1f8c30269431e9f13a7ba65751abc815980d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A5=BA=E5=AD=90w?= Date: Thu, 14 Feb 2019 01:47:48 +0800 Subject: [PATCH] Support reverse proxy with path rewrite (#127) --- api/application.go | 30 +++++++++++++---------------- api/application_test.go | 10 +++++----- docs/spec.json | 2 +- docs/swagger.go | 11 +++++++---- docs/swagger_test.go | 3 ++- docs/ui.go | 7 ++++++- model/application.go | 2 +- ui/package.json | 1 + ui/src/application/Applications.tsx | 3 ++- ui/src/index.tsx | 5 +++-- ui/src/message/Message.tsx | 3 ++- 11 files changed, 43 insertions(+), 34 deletions(-) diff --git a/api/application.go b/api/application.go index fb23a7d..6a501a3 100644 --- a/api/application.go +++ b/api/application.go @@ -8,7 +8,6 @@ import ( "path/filepath" "github.com/gin-gonic/gin" - "github.com/gotify/location" "github.com/gotify/server/auth" "github.com/gotify/server/model" "github.com/h2non/filetype" @@ -70,7 +69,7 @@ func (a *ApplicationAPI) CreateApplication(ctx *gin.Context) { app.UserID = auth.GetUserID(ctx) app.Internal = false a.DB.CreateApplication(&app) - ctx.JSON(200, withAbsoluteURL(ctx, &app)) + ctx.JSON(200, withResolvedImage(&app)) } } @@ -102,7 +101,7 @@ func (a *ApplicationAPI) GetApplications(ctx *gin.Context) { userID := auth.GetUserID(ctx) apps := a.DB.GetApplicationsByUser(userID) for _, app := range apps { - withAbsoluteURL(ctx, app) + withResolvedImage(app) } ctx.JSON(200, apps) } @@ -210,7 +209,7 @@ func (a *ApplicationAPI) UpdateApplication(ctx *gin.Context) { a.DB.UpdateApplication(app) - ctx.JSON(200, withAbsoluteURL(ctx, app)) + ctx.JSON(200, withResolvedImage(app)) } } else { ctx.AbortWithError(404, fmt.Errorf("app with id %d doesn't exists", id)) @@ -302,13 +301,22 @@ func (a *ApplicationAPI) UploadApplicationImage(ctx *gin.Context) { app.Image = name + ext a.DB.UpdateApplication(app) - ctx.JSON(200, withAbsoluteURL(ctx, app)) + ctx.JSON(200, withResolvedImage(app)) } else { ctx.AbortWithError(404, fmt.Errorf("client with id %d doesn't exists", id)) } }) } +func withResolvedImage(app *model.Application) *model.Application { + if app.Image == "" { + app.Image = "static/defaultapp.png" + } else { + app.Image = "image/" + app.Image + } + return app +} + func (a *ApplicationAPI) applicationExists(token string) bool { return a.DB.GetApplicationByToken(token) != nil } @@ -319,15 +327,3 @@ func exist(path string) bool { } return true } - -func withAbsoluteURL(ctx *gin.Context, app *model.Application) *model.Application { - url := location.Get(ctx) - - if app.Image == "" { - url.Path = "static/defaultapp.png" - } else { - url.Path = "image/" + app.Image - } - app.Image = url.String() - return app -} diff --git a/api/application_test.go b/api/application_test.go index 9341ad1..766619a 100644 --- a/api/application_test.go +++ b/api/application_test.go @@ -130,7 +130,7 @@ func (s *ApplicationSuite) Test_CreateApplication_returnsApplicationWithID() { ID: 1, Token: firstApplicationToken, Name: "custom_name", - Image: "http://example.com/static/defaultapp.png", + Image: "static/defaultapp.png", UserID: 5, } assert.Equal(s.T(), 200, s.recorder.Code) @@ -162,8 +162,8 @@ func (s *ApplicationSuite) Test_GetApplications() { s.a.GetApplications(s.ctx) assert.Equal(s.T(), 200, s.recorder.Code) - first.Image = "http://example.com/static/defaultapp.png" - second.Image = "http://example.com/static/defaultapp.png" + first.Image = "static/defaultapp.png" + second.Image = "static/defaultapp.png" test.BodyEquals(s.T(), []*model.Application{first, second}, s.recorder) } @@ -180,8 +180,8 @@ func (s *ApplicationSuite) Test_GetApplications_WithImage() { s.a.GetApplications(s.ctx) assert.Equal(s.T(), 200, s.recorder.Code) - first.Image = "http://example.com/image/abcd.jpg" - second.Image = "http://example.com/static/defaultapp.png" + first.Image = "image/abcd.jpg" + second.Image = "static/defaultapp.png" test.BodyEquals(s.T(), []*model.Application{first, second}, s.recorder) } diff --git a/docs/spec.json b/docs/spec.json index cdc77d1..bc2bc51 100644 --- a/docs/spec.json +++ b/docs/spec.json @@ -1804,7 +1804,7 @@ "type": "string", "x-go-name": "Image", "readOnly": true, - "example": "https://example.com/image.jpeg" + "example": "image/image.jpeg" }, "internal": { "description": "Whether the application is an internal application. Internal applications should not be deleted.", diff --git a/docs/swagger.go b/docs/swagger.go index 2029209..914c37a 100644 --- a/docs/swagger.go +++ b/docs/swagger.go @@ -10,11 +10,14 @@ import ( // Serve serves the documentation. func Serve(ctx *gin.Context) { - url := location.Get(ctx) - ctx.Writer.WriteString(get(url.Host)) + base := location.Get(ctx).Host + if basePathFromQuery := ctx.Query("base"); basePathFromQuery != "" { + base = basePathFromQuery + } + ctx.Writer.WriteString(get(base)) } -func get(host string) string { +func get(base string) string { box := packr.NewBox("./") - return strings.Replace(box.String("spec.json"), "localhost", host, 1) + return strings.Replace(box.String("spec.json"), "localhost", base, 1) } diff --git a/docs/swagger_test.go b/docs/swagger_test.go index 945bb7a..a6559d5 100644 --- a/docs/swagger_test.go +++ b/docs/swagger_test.go @@ -16,12 +16,13 @@ func TestServe(t *testing.T) { ctx, _ := gin.CreateTestContext(recorder) withURL(ctx, "http", "example.com") - ctx.Request = httptest.NewRequest("GET", "/swagger", nil) + ctx.Request = httptest.NewRequest("GET", "/swagger?base="+url.QueryEscape("127.0.0.1/proxy/"), nil) Serve(ctx) content := recorder.Body.String() assert.NotEmpty(t, content) + assert.Contains(t, content, "127.0.0.1/proxy/") } func withURL(ctx *gin.Context, scheme, host string) { diff --git a/docs/ui.go b/docs/ui.go index 46ae952..2949b48 100644 --- a/docs/ui.go +++ b/docs/ui.go @@ -39,10 +39,15 @@ var ui = `