Skip to content

Commit 19ce90e

Browse files
Bump to v0.0.19 - Add Accept-Patch/Accept-Put headers to 404 responses
Fixes JavaScriptSolidServer#1 - PodOS compatibility for creating new resources - Add getNotFoundHeaders() to return proper headers for 404 responses - Update handleGet, handleHead, handleDelete, handlePatch to include Accept-Patch, Accept-Put, Allow headers on 404 responses - Set DATA_ROOT env var from --root config option for module consistency
1 parent 50ea82d commit 19ce90e

4 files changed

Lines changed: 51 additions & 2 deletions

File tree

bin/jss.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ program
5959
try {
6060
const config = await loadConfig(options, options.config);
6161

62+
// Set DATA_ROOT env var so all modules use the same data directory
63+
process.env.DATA_ROOT = path.resolve(config.root);
64+
6265
if (options.printConfig) {
6366
printConfig(config);
6467
process.exit(0);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "javascript-solid-server",
3-
"version": "0.0.18",
3+
"version": "0.0.19",
44
"description": "A minimal, fast Solid server",
55
"main": "src/index.js",
66
"type": "module",

src/handlers/resource.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as storage from '../storage/filesystem.js';
2-
import { getAllHeaders } from '../ldp/headers.js';
2+
import { getAllHeaders, getNotFoundHeaders } from '../ldp/headers.js';
33
import { generateContainerJsonLd, serializeJsonLd } from '../ldp/container.js';
44
import { isContainer, getContentType, isRdfContentType, getEffectiveUrlPath } from '../utils/url.js';
55
import { parseN3Patch, applyN3Patch, validatePatch } from '../patch/n3-patch.js';
@@ -37,6 +37,10 @@ export async function handleGet(request, reply) {
3737
const stats = await storage.stat(storagePath);
3838

3939
if (!stats) {
40+
const origin = request.headers.origin;
41+
const connegEnabled = request.connegEnabled || false;
42+
const headers = getNotFoundHeaders({ resourceUrl, origin, connegEnabled });
43+
Object.entries(headers).forEach(([k, v]) => reply.header(k, v));
4044
return reply.code(404).send({ error: 'Not Found' });
4145
}
4246

@@ -219,6 +223,10 @@ export async function handleHead(request, reply) {
219223
const stats = await storage.stat(storagePath);
220224

221225
if (!stats) {
226+
const origin = request.headers.origin;
227+
const connegEnabled = request.connegEnabled || false;
228+
const headers = getNotFoundHeaders({ resourceUrl, origin, connegEnabled });
229+
Object.entries(headers).forEach(([k, v]) => reply.header(k, v));
222230
return reply.code(404).send();
223231
}
224232

@@ -366,6 +374,10 @@ export async function handleDelete(request, reply) {
366374
// Check if resource exists and get current ETag
367375
const stats = await storage.stat(storagePath);
368376
if (!stats) {
377+
const origin = request.headers.origin;
378+
const connegEnabled = request.connegEnabled || false;
379+
const headers = getNotFoundHeaders({ resourceUrl, origin, connegEnabled });
380+
Object.entries(headers).forEach(([k, v]) => reply.header(k, v));
369381
return reply.code(404).send({ error: 'Not Found' });
370382
}
371383

@@ -442,6 +454,10 @@ export async function handlePatch(request, reply) {
442454
// Check if resource exists
443455
const stats = await storage.stat(storagePath);
444456
if (!stats) {
457+
const origin = request.headers.origin;
458+
const connegEnabled = request.connegEnabled || false;
459+
const headers = getNotFoundHeaders({ resourceUrl, origin, connegEnabled });
460+
Object.entries(headers).forEach(([k, v]) => reply.header(k, v));
445461
return reply.code(404).send({ error: 'Not Found' });
446462
}
447463

src/ldp/headers.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,33 @@ export function getAllHeaders({ isContainer = false, etag = null, contentType =
108108
...getCorsHeaders(origin)
109109
};
110110
}
111+
112+
/**
113+
* Get headers for 404 responses (non-existent resources)
114+
* These headers tell clients what methods are supported for creating the resource
115+
* @param {object} options
116+
* @returns {object}
117+
*/
118+
export function getNotFoundHeaders({ resourceUrl = null, origin = null, connegEnabled = false }) {
119+
// Determine if this would be a container based on URL ending with /
120+
const isContainer = resourceUrl?.endsWith('/') || false;
121+
const aclUrl = resourceUrl ? getAclUrl(resourceUrl, isContainer) : null;
122+
123+
// Get Accept-* headers
124+
const acceptHeaders = getAcceptHeaders(connegEnabled, isContainer);
125+
126+
const headers = {
127+
...getCorsHeaders(origin),
128+
'Link': aclUrl ? `<${aclUrl}>; rel="acl"` : '',
129+
'Accept-Patch': 'text/n3, application/sparql-update',
130+
'Accept-Put': acceptHeaders['Accept-Put'] || 'application/ld+json, */*',
131+
'Allow': 'GET, HEAD, PUT, PATCH, OPTIONS' + (isContainer ? ', POST' : ''),
132+
'Vary': connegEnabled ? 'Accept, Authorization, Origin' : 'Authorization, Origin'
133+
};
134+
135+
if (isContainer && acceptHeaders['Accept-Post']) {
136+
headers['Accept-Post'] = acceptHeaders['Accept-Post'];
137+
}
138+
139+
return headers;
140+
}

0 commit comments

Comments
 (0)