[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/bourgeoa/JavaScriptSolidServer/patchAppend/src/ldp/headers.js [Back]  [Original]

/**
 * LDP (Linked Data Platform) header utilities
 */

import { getAcceptHeaders, getVaryHeader } 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 = [`; rel="type"`];

  if (isContainer) {
    links.push(`; rel="type"`);
    links.push(`; rel="type"`);
  }

  // Add acl link for auxiliary resource discovery
  if (aclUrl) {
    links.push(`; 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, mashlibEnabled = false, updatesVia = null }) {
  // Calculate ACL URL if resource URL provided
  const aclUrl = resourceUrl ? getAclUrl(resourceUrl, isContainer) : null;

  const headers = {
    'Link': getLinkHeader(isContainer, aclUrl),
    'Accept-Patch': 'text/n3, application/sparql-update',
    'Accept-Ranges': isContainer ? 'none' : 'bytes',
    'Allow': 'GET, HEAD, PUT, DELETE, PATCH, OPTIONS' + (isContainer ? ', POST' : ''),
    'Vary': getVaryHeader(connegEnabled, mashlibEnabled)
  };

  // Only set WAC-Allow if explicitly provided (otherwise the auth hook sets it)
  if (wacAllow) {
    headers['WAC-Allow'] = wacAllow;
  }

  // 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, Range, Slug, Origin',
    'Access-Control-Expose-Headers': 'Accept-Patch, Accept-Post, Accept-Ranges, Allow, Content-Length, Content-Range, Content-Type, ETag, Link, Location, Updates-Via, WAC-Allow, X-Cost, X-Balance, X-Pay-Currency',
    '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, mashlibEnabled = false, updatesVia = null }) {
  return {
    ...getResponseHeaders({ isContainer, etag, contentType, resourceUrl, wacAllow, connegEnabled, mashlibEnabled, 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, mashlibEnabled = 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 ? `; 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': getVaryHeader(connegEnabled, mashlibEnabled)
  };

  if (isContainer && acceptHeaders['Accept-Post']) {
    headers['Accept-Post'] = acceptHeaders['Accept-Post'];
  }

  return headers;
}

Web Proxy Viewer  |  New URL  |  Original Page