What happened?
Trying to reverse proxy CouchDB for Obsidian's Self-hosted LiveSync plugin. Hit two CORS bugs in the proxy that took a while to find. CouchDB itself returns the correct ACAO when tested directly - verified with curl, it echoes app://obsidian.md as configured. The mangling happens in Cosmos.
With CORSOrigin left empty (the default), Cosmos overrides the upstream's correct ACAO and writes the route's Host field directly into the header — bare hostname, no scheme. Browsers reject it because that isn't a valid origin. Looks like the empty-default fallback writes Host without prepending https://.
Setting CORSOrigin to a comma-separated list (e.g. app://obsidian.md, capacitor://localhost, http://localhost) puts all three values into a single ACAO header. but the spec only allows one value per header: when given a list, the proxy should match the request's Origin against the list and echo back the matching one. Currently you can only use one origin at a time, which means desktop and mobile clients of the same app can't share a route.
What should have happened?
With CORSOrigin empty, the proxy should pass through the upstream's Access-Control-Allow-Origin unchanged, or if it must write its own value, prepend the route's scheme (https://host/) so the result is at least a syntactically valid origin.
With CORSOrigin set to a comma-separated list, the proxy should compare the request's Origin header against the configured list and, if it matches one, echo that single value back in ACAO. If no match, omit the header (or return without CORS approval). One header, one value, per spec.
How to reproduce the bug?
- Create any route to a backend that does its own CORS (CouchDB is a clean test case).
curl -i -X OPTIONS https://your.route/ -H "Origin: app://obsidian.md" -H "Access-Control-Request-Method: GET"
- Observe ACAO in the response is the bare route hostname, not what the upstream returned.
- Set CORSOrigin to a comma-separated list, repeat — observe the whole list in one header.
Relevant log output
Other details
No response
System details
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
What happened?
Trying to reverse proxy CouchDB for Obsidian's Self-hosted LiveSync plugin. Hit two CORS bugs in the proxy that took a while to find. CouchDB itself returns the correct ACAO when tested directly - verified with curl, it echoes
app://obsidian.mdas configured. The mangling happens in Cosmos.With CORSOrigin left empty (the default), Cosmos overrides the upstream's correct ACAO and writes the route's Host field directly into the header — bare hostname, no scheme. Browsers reject it because that isn't a valid origin. Looks like the empty-default fallback writes Host without prepending
https://.Setting CORSOrigin to a comma-separated list (e.g.
app://obsidian.md, capacitor://localhost, http://localhost) puts all three values into a single ACAO header. but the spec only allows one value per header: when given a list, the proxy should match the request's Origin against the list and echo back the matching one. Currently you can only use one origin at a time, which means desktop and mobile clients of the same app can't share a route.What should have happened?
With CORSOrigin empty, the proxy should pass through the upstream's Access-Control-Allow-Origin unchanged, or if it must write its own value, prepend the route's scheme (https://host/) so the result is at least a syntactically valid origin.
With CORSOrigin set to a comma-separated list, the proxy should compare the request's Origin header against the configured list and, if it matches one, echo that single value back in ACAO. If no match, omit the header (or return without CORS approval). One header, one value, per spec.
How to reproduce the bug?
curl -i -X OPTIONS https://your.route/ -H "Origin: app://obsidian.md" -H "Access-Control-Request-Method: GET"Relevant log output
Other details
No response
System details