Skip to content

config/public: cache blob content#1810

Open
alxndrsn wants to merge 55 commits into
getodk:masterfrom
alxndrsn:hero-image-chachine
Open

config/public: cache blob content#1810
alxndrsn wants to merge 55 commits into
getodk:masterfrom
alxndrsn:hero-image-chachine

Conversation

@alxndrsn
Copy link
Copy Markdown
Contributor

@alxndrsn alxndrsn commented Apr 21, 2026

Closes getodk/central#1822

What has been done to verify that this works as intended?

  • tested locally
  • new integration tests with & without S3 blob support enabled
  • new e2e test with s3 enable

Why is this the best possible solution? Were any other approaches considered?

Alternatives
  1. Don't upload config blobs to s3 in the first place
  • 👍 sounds like a decent alternative
  1. Upload to s3, but use public URLs instead of presigned links
  • 👎 sounds fiddly and (maybe?) reliant on more complicated config of buckets, and validating configuration stored outside odk-central repos
  1. Catch requests for these blobs in nginx and transparently proxy them to the presigned URLs
  • 👎 sounds fiddly to implement and test, but on the other hand
  • 👍 might make for a useful example of how this level of caching could be achieved for other blobs
  • 👍 moves work from node upstream to nginx

How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?

Should make the login page load faster.

Does this change require updates to the API documentation? If so, please update docs/api.yaml as part of this PR.

304 responses have been added to the API documentation.

Before submitting this PR, please make sure you have:

  • run make test and confirmed all checks still pass, or witnessed Github completing all checks with success
  • verified that any code from external sources are properly credited in comments or that everything is internally sourced

@alxndrsn alxndrsn marked this pull request as ready for review April 25, 2026 11:26
Comment thread lib/util/blob.js
Comment thread test/integration/api/config.js Outdated
@alxndrsn alxndrsn requested a review from matthew-white May 5, 2026 11:11
Comment thread lib/resources/config.js Outdated
Comment thread lib/resources/config.js Outdated

if (!frame.isPublic) return Problem.user.insufficientRights();

response.set('Cache-Control', request.query.ts ? 'max-age=31536000' : 'no-cache');
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.

What do you think about moving this logic to getConfig()? To me, the only difference between /v1/config/:key and /v1/config/public/:key is how auth works. I'd expect caching to work the same between the two.

Practically, moving the logic wouldn't have any user-facing effect, since Frontend is only using /v1/config/public/:key for these images; Frontend doesn't need /v1/config/:key to do caching. But to me, it'd be a little clearer to handle the logic in getConfig(). Doing so would require passing request and response to getConfig().

I don't have strong feelings about this one. Mostly I just wanted to throw it out there to see what you thought.

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.

Or is the idea that /v1/config/public/:key is already public, so there's no concern about sensitive data ending up in a cache somewhere?

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.

On that point, I'm now realizing that even when request.query.ts is falsey, the endpoint sets the header to no-cache, which is different from the default of private, no-cache that's set by lib/http/service.js. To me, the absence of private is confirmation of the intention that only the public endpoint should have these differences in caching. 👍

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.

Now I'm wondering whether a code comment explaining some of this reasoning would be helpful. 🤔

(Sorry for all the comments here!)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

no-cache is to allow for public caching, and revalidation via ETag. I've refactored cache header handling to be more descriptive - please take a look.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think this change also makes it clearer why cache headers would be handled differently for /config/public/:key to /config/:key.

Comment thread test/integration/api/config.js Outdated
@alxndrsn alxndrsn requested a review from matthew-white May 7, 2026 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No browser caching for login logo and hero images on S3

2 participants