Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion api/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func buildWithPaging(ctx *gin.Context, paging *pagingParams, messages []*model.M
useMessages = messages[:len(messages)-1]
since = useMessages[len(useMessages)-1].ID
url := location.Get(ctx)
url.Path = ctx.Request.URL.Path
url.Path = withForwardedPrefix(ctx, ctx.Request.URL.Path)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer if this would be changed to be consistent with the changes done in #127, so that a relative path is returned like it's now with the application images.

{"id": 2, "image": "static/defaultapp.png", ...},

Example in the message api:

"paging": {
    "limit": 100,
    "next": "/message?limit=100&since=23",
    "since": 23,
    "size": 100
}

or

"paging": {
    "limit": 100,
    "next": "/application/3/message?limit=100&since=23",
    "since": 23,
    "size": 100
}

query := url.Query()
query.Add("limit", strconv.Itoa(paging.Limit))
query.Add("since", strconv.FormatUint(uint64(since), 10))
Expand All @@ -118,6 +118,20 @@ func buildWithPaging(ctx *gin.Context, paging *pagingParams, messages []*model.M
}
}

// withForwardedPrefix prepends the reverse-proxy path prefix to the given
// request path. Reverse proxies that strip a subpath before forwarding the
// request (e.g. Caddy's `uri strip_prefix /gotify`) can announce the stripped
// prefix via the X-Forwarded-Prefix header, so that URLs emitted by gotify —
// like the paging `next` link — keep pointing at the externally reachable path
// instead of dropping the prefix. See #664.
func withForwardedPrefix(ctx *gin.Context, path string) string {
prefix := strings.Trim(ctx.GetHeader("X-Forwarded-Prefix"), "/")
if prefix == "" {
return path
}
return "/" + prefix + "/" + strings.TrimPrefix(path, "/")
}

func withPaging(ctx *gin.Context, f func(pagingParams *pagingParams)) {
params := &pagingParams{Limit: 100}
if err := ctx.MustBindWith(params, binding.Query); err == nil {
Expand Down
27 changes: 27 additions & 0 deletions api/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,33 @@ func (s *MessageSuite) Test_GetMessages_WithLimit_ReturnsNext() {
test.BodyEquals(s.T(), expected, s.recorder)
}

func (s *MessageSuite) Test_GetMessages_WithLimit_BehindProxyPrefix_ReturnsNextWithPrefix() {
user := s.db.User(5)
app1 := user.App(1)
app2 := user.App(2)
var messages []*model.Message
for i := 100; i >= 1; i -= 2 {
one := app2.NewMessage(uint(i))
two := app1.NewMessage(uint(i - 1))
messages = append(messages, &one, &two)
}

// The reverse proxy strips the /gotify prefix, so gotify receives /message,
// but announces the stripped prefix via X-Forwarded-Prefix. The emitted
// next url must keep the prefix. See #664.
s.withURL("http", "example.com", "/message", "limit=5")
s.ctx.Request.Header.Set("X-Forwarded-Prefix", "/gotify")
test.WithUser(s.ctx, 5)
s.a.GetMessages(s.ctx)

expected := &model.PagedMessages{
Paging: model.Paging{Limit: 5, Size: 5, Since: 96, Next: "http://example.com/gotify/message?limit=5&since=96"},
Messages: toExternalMessages(messages[:5]),
}

test.BodyEquals(s.T(), expected, s.recorder)
}

func (s *MessageSuite) Test_GetMessages_WithLimit_WithSince_ReturnsNext() {
user := s.db.User(5)
app1 := user.App(1)
Expand Down