-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathheaders.js
More file actions
140 lines (119 loc) · 4.46 KB
/
headers.js
File metadata and controls
140 lines (119 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* LDP (Linked Data Platform) header utilities
*/
import { getAcceptHeaders } from '../rdf/conneg.js';
const LDP = 'http://www.w3.org/ns/ldp#';
/**
* Get Link headers for a resource
* @param {boolean} isContainer
* @param {string} aclUrl - URL to the ACL resource
* @returns {string}
*/
export function getLinkHeader(isContainer, aclUrl = null) {
const links = [`<${LDP}Resource>; rel="type"`];
if (isContainer) {
links.push(`<${LDP}Container>; rel="type"`);
links.push(`<${LDP}BasicContainer>; rel="type"`);
}
// Add acl link for auxiliary resource discovery
if (aclUrl) {
links.push(`<${aclUrl}>; rel="acl"`);
}
return links.join(', ');
}
/**
* Get the ACL URL for a resource
* @param {string} resourceUrl - Full URL of the resource
* @param {boolean} isContainer - Whether the resource is a container
* @returns {string} ACL URL
*/
export function getAclUrl(resourceUrl, isContainer) {
if (isContainer) {
// Container ACL: /path/.acl
const base = resourceUrl.endsWith('/') ? resourceUrl : resourceUrl + '/';
return base + '.acl';
}
// Resource ACL: /path/file.acl
return resourceUrl + '.acl';
}
/**
* Get standard LDP response headers
* @param {object} options
* @returns {object}
*/
export function getResponseHeaders({ isContainer = false, etag = null, contentType = null, resourceUrl = null, wacAllow = null, connegEnabled = false, updatesVia = null }) {
// Calculate ACL URL if resource URL provided
const aclUrl = resourceUrl ? getAclUrl(resourceUrl, isContainer) : null;
const headers = {
'Link': getLinkHeader(isContainer, aclUrl),
'WAC-Allow': wacAllow || 'user="read write append control", public="read write append"',
'Accept-Patch': 'text/n3, application/sparql-update',
'Allow': 'GET, HEAD, PUT, DELETE, PATCH, OPTIONS' + (isContainer ? ', POST' : ''),
'Vary': connegEnabled ? 'Accept, Authorization, Origin' : 'Authorization, Origin'
};
// Add Accept-* headers (conneg-aware)
const acceptHeaders = getAcceptHeaders(connegEnabled, isContainer);
Object.assign(headers, acceptHeaders);
// Add Updates-Via header for WebSocket notifications discovery
if (updatesVia) {
headers['Updates-Via'] = updatesVia;
}
if (etag) {
headers['ETag'] = etag;
}
if (contentType) {
headers['Content-Type'] = contentType;
}
return headers;
}
/**
* Get CORS headers
* @param {string} origin
* @returns {object}
*/
export function getCorsHeaders(origin) {
return {
'Access-Control-Allow-Origin': origin || '*',
'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers': 'Accept, Authorization, Content-Type, DPoP, If-Match, If-None-Match, Link, Slug, Origin',
'Access-Control-Expose-Headers': 'Accept-Patch, Accept-Post, Allow, Content-Type, ETag, Link, Location, Updates-Via, WAC-Allow',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Max-Age': '86400'
};
}
/**
* Get all headers combined
* @param {object} options
* @returns {object}
*/
export function getAllHeaders({ isContainer = false, etag = null, contentType = null, origin = null, resourceUrl = null, wacAllow = null, connegEnabled = false, updatesVia = null }) {
return {
...getResponseHeaders({ isContainer, etag, contentType, resourceUrl, wacAllow, connegEnabled, updatesVia }),
...getCorsHeaders(origin)
};
}
/**
* Get headers for 404 responses (non-existent resources)
* These headers tell clients what methods are supported for creating the resource
* @param {object} options
* @returns {object}
*/
export function getNotFoundHeaders({ resourceUrl = null, origin = null, connegEnabled = false }) {
// Determine if this would be a container based on URL ending with /
const isContainer = resourceUrl?.endsWith('/') || false;
const aclUrl = resourceUrl ? getAclUrl(resourceUrl, isContainer) : null;
// Get Accept-* headers
const acceptHeaders = getAcceptHeaders(connegEnabled, isContainer);
const headers = {
...getCorsHeaders(origin),
'Link': aclUrl ? `<${aclUrl}>; rel="acl"` : '',
'Accept-Patch': 'text/n3, application/sparql-update',
'Accept-Put': acceptHeaders['Accept-Put'] || 'application/ld+json, */*',
'Allow': 'GET, HEAD, PUT, PATCH, OPTIONS' + (isContainer ? ', POST' : ''),
'Vary': connegEnabled ? 'Accept, Authorization, Origin' : 'Authorization, Origin'
};
if (isContainer && acceptHeaders['Accept-Post']) {
headers['Accept-Post'] = acceptHeaders['Accept-Post'];
}
return headers;
}