Skip to content

Commit

Permalink
fix: Include expires header on 304 cache hit (#438)
Browse files Browse the repository at this point in the history
When configured with a TTL, the relay proxy will include an `expires`
header when a flag or segment is first requested. This informs the PHP
SDK how long it can cache the response.

Once the SDK makes another request, it is possible the flag still hasn't
changed. In that situation, we should return a new `expires` header.
Otherwise, the PHP SDK will have no idea how long it should cache this
new response for, resulting in it re-fetching on demand going forward.
  • Loading branch information
keelerm84 authored Sep 6, 2024
1 parent 8340b23 commit b24370e
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 9 deletions.
2 changes: 2 additions & 0 deletions relay/endpoints_php_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func TestEndpointsPHPPolling(t *testing.T) {
result, _ := st.DoRequest(r, p.relay)

assert.Equal(t, http.StatusNotModified, result.StatusCode)
assert.NotEmpty(t, result.Header.Get("Expires"))
})

t.Run("query with different ETag is cached", func(t *testing.T) {
Expand All @@ -76,6 +77,7 @@ func TestEndpointsPHPPolling(t *testing.T) {
result, _ := st.DoRequest(r, p.relay)

assert.Equal(t, http.StatusOK, result.StatusCode)
assert.NotEmpty(t, result.Header.Get("Expires"))
})
}
}
Expand Down
19 changes: 10 additions & 9 deletions relay/relay_endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,15 +297,6 @@ func pollFlagOrSegment(clientContext relayenv.EnvContext, kind ldstoretypes.Data

func writeCacheableJSONResponse(w http.ResponseWriter, req *http.Request, clientContext relayenv.EnvContext,
bytes []byte, etagValue string) {
etag := fmt.Sprintf("relay-%s", etagValue) // just to make it extra clear that these are relay-specific etags
if cachedEtag := req.Header.Get("If-None-Match"); cachedEtag != "" {
if cachedEtag == etag {
w.WriteHeader(http.StatusNotModified)
return
}
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Etag", etag)
ttl := clientContext.GetTTL()
if ttl > 0 {
w.Header().Set("Vary", "Authorization")
Expand All @@ -315,7 +306,17 @@ func writeCacheableJSONResponse(w http.ResponseWriter, req *http.Request, client
// HTTP cache in front of ld-relay, multiple clients hitting the cache at different times
// will all see the same expiration time.
}

etag := fmt.Sprintf("relay-%s", etagValue) // just to make it extra clear that these are relay-specific etags
if cachedEtag := req.Header.Get("If-None-Match"); cachedEtag == etag {
w.WriteHeader(http.StatusNotModified)
return
}

w.Header().Set("Content-Type", "application/json")
w.Header().Set("Etag", etag)
w.WriteHeader(http.StatusOK)

_, _ = w.Write(bytes)
}

Expand Down

0 comments on commit b24370e

Please sign in to comment.