mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-09 21:02:19 +00:00
fix(server): declare Allow: GET on the new 405 responses
RFC 9110 section 15.5.6 requires a 405 to name the methods it accepts, and /api/radio/stations already does this in-tree. Thanks to kvnloo for catching it on review. The same gap on the pre-existing handlers is tracked in #809 and is deliberately left alone here.
This commit is contained in:
1 parent
fb6b4e34f0
commit
2e5dfce1af
6 files changed
+15
-4
No files matched your search
@@ -4072,7 +4072,7 @@ are omitted rather than framing the wrong part of the globe.
|
||||
- `/api/overpass` is bounded by body/response caps, per-client/global rate limits, concurrency limits, operator-configured upstreams, in-flight dedupe, cache bounds, and static validation that every selector is spatially bounded.
|
||||
- `/api/military-installations` uses an independent limiter with the same 90-per-client/300-global one-minute bounds, so viewport installation refreshes never consume `/api/overpass` annotation capacity.
|
||||
- `/api/route` proxies bounded OSRM route requests for annotation routes, with profile allowlisting, distance caps, response caps, caching, and sanitized "no route found" errors.
|
||||
- `/api/opensky`, `/api/adsblol/mil`, and `/api/route` are read-only query proxies and answer `405 Method Not Allowed` to anything but `GET`, as `/api/geocode` and the other query proxies already did. The refusal precedes rate limiting and any upstream call.
|
||||
- `/api/opensky`, `/api/adsblol/mil`, and `/api/route` are read-only query proxies and answer `405 Method Not Allowed` to anything but `GET`, as `/api/geocode` and the other query proxies already did, declaring `Allow: GET` with it as `/api/radio/stations` does. The refusal precedes rate limiting and any upstream call.
|
||||
- Track endpoints: `/api/ais-live/track?mmsi=` (server-accumulated ring buffers; sub-route handled before the rows snapshot), `/api/opensky-track?icao24=` (OAuth, 60s cache, sanitized errors, independent OpenSky credit bucket), `/api/adsblol/trace?hex=` (60s cache, 5MB cap, ODbL attribution required in UI).
|
||||
- Realtime debug logs redact API keys, bearer tokens, client secrets, and image data URLs before writing to disk; request bodies are size-capped.
|
||||
- `/api/realtime/debug-log` enforces an always-on 120-per-client/400-global one-minute limiter (not the opt-in `GEV_RATELIMIT_OPENAI_PER_MIN` bucket the cost-bearing OpenAI routes share), appends asynchronously through a serialized queue, and rotates `realtime-conversations.jsonl` at 32 MB keeping one prior generation, so the sink is bounded at twice that regardless of session length. A malformed record answers 400 and a failed write 500, both with a fixed message.
|
||||
|
||||
@@ -71,7 +71,10 @@ export function adsbLolProxy() {
|
||||
// Read-only snapshot endpoint; match the method contract its sibling
|
||||
// query proxies already declare instead of serving every verb alike.
|
||||
if (req.method !== 'GET') {
|
||||
res.writeHead(405, { 'Content-Type': 'application/json' });
|
||||
res.writeHead(405, {
|
||||
'Content-Type': 'application/json',
|
||||
Allow: 'GET',
|
||||
});
|
||||
res.end(JSON.stringify({ error: 'Method Not Allowed' }));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -354,7 +354,10 @@ export function openSkyProxy() {
|
||||
// /api/geocode and the other query proxies state it, rather than
|
||||
// answering any verb with the same body and ignoring the request body.
|
||||
if (req.method !== 'GET') {
|
||||
res.writeHead(405, { 'Content-Type': 'application/json' });
|
||||
res.writeHead(405, {
|
||||
'Content-Type': 'application/json',
|
||||
Allow: 'GET',
|
||||
});
|
||||
res.end(JSON.stringify({ error: 'Method Not Allowed' }));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ export function installRouteMiddleware(
|
||||
// The documented shape above is a GET with query parameters; say so,
|
||||
// the way the other query proxies do, instead of answering any verb.
|
||||
if (req.method !== 'GET') {
|
||||
res.writeHead(405, { 'Content-Type': 'application/json' });
|
||||
res.writeHead(405, { 'Content-Type': 'application/json', Allow: 'GET' });
|
||||
res.end(JSON.stringify({ error: 'Method Not Allowed' }));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -398,6 +398,9 @@ test('the aircraft snapshot routes decline a non-GET before any upstream work',
|
||||
for (const method of ['POST', 'PUT', 'DELETE', 'PATCH']) {
|
||||
const response = await request(route, '/', method);
|
||||
assert.equal(response.statusCode, 405, `${method} ${route}`);
|
||||
// RFC 9110 section 15.5.6 requires a 405 to name the methods it does
|
||||
// accept, which is what `/api/radio/stations` already does in-tree.
|
||||
assert.equal(response.headers.allow, 'GET', `${method} ${route}`);
|
||||
assert.deepEqual(JSON.parse(response.body), {
|
||||
error: 'Method Not Allowed',
|
||||
});
|
||||
|
||||
@@ -498,6 +498,8 @@ test('the routing proxy declines a non-GET before rate limiting or upstream', as
|
||||
method,
|
||||
);
|
||||
assert.equal(response.statusCode, 405, method);
|
||||
// RFC 9110 section 15.5.6 requires a 405 to name the methods it accepts.
|
||||
assert.equal(response.headers.allow, 'GET', method);
|
||||
assert.deepEqual(response.body, { error: 'Method Not Allowed' });
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user