;; disfluid, implementation of the Solid specification ;; Copyright (C) 2020, 2021 Vivien Kraus ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU Affero General Public License as ;; published by the Free Software Foundation, either version 3 of the ;; License, or (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU Affero General Public License for more details. ;; You should have received a copy of the GNU Affero General Public License ;; along with this program. If not, see . (define-module (webid-oidc server read) #:use-module (webid-oidc errors) #:use-module (webid-oidc server resource path) #:use-module (webid-oidc server resource content) #:use-module (webid-oidc cache) #:use-module (webid-oidc fetch) #:use-module (webid-oidc http-link) #:use-module (webid-oidc server resource wac) #:use-module (webid-oidc web-i18n) #:use-module ((webid-oidc stubs) #:prefix stubs:) #:use-module (webid-oidc rdf-index) #:use-module ((webid-oidc refresh-token) #:prefix refresh:) #:use-module ((webid-oidc parameters) #:prefix p:) #:use-module (web uri) #:use-module (web response) #:use-module (rdf rdf) #:use-module (turtle tordf) #:use-module (turtle fromrdf) #:use-module (rnrs bytevectors) #:use-module (ice-9 exceptions) #:use-module (ice-9 receive) #:use-module (ice-9 optargs) #:use-module (ice-9 iconv) #:use-module (ice-9 textual-ports) #:use-module (ice-9 binary-ports) #:use-module (ice-9 threads) #:use-module (rnrs bytevectors) #:use-module (oop goops) #:export ( &auxiliary-resource-absent make-auxiliary-resource-absent auxiliary-resource-absent? auxiliary-resource-absent-base-path auxiliary-resource-absent-path-type read )) (define-exception-type &auxiliary-resource-absent &external-error make-auxiliary-resource-absent auxiliary-resource-absent? (base-path auxiliary-resource-absent-base-path) (path-type auxiliary-resource-absent-path-type)) (define* (read server-name owner user path) (declare-link-header!) (parameterize ((current-content-cache (make ))) (check-acl-can-read server-name path owner user) (receive (base-path path-type) (base-path path) (let ((container? (container-path? path)) (root? (root-path? path)) (acl? (equal? path-type (string->uri "http://www.w3.org/ns/auth/acl#accessControl"))) (description? (equal? path-type (string->uri "https://www.w3.org/ns/iana/link-relations/relation#describedby")))) (receive (main auxiliary) (read-path base-path) (let ((relevant (if path-type (assoc-ref auxiliary path-type) main)) (needs-meta? (case (content-type main) ((text/turtle) #f) (else #t))) (needs-acl? (not acl?)) (allow (cond (root? '(GET HEAD OPTIONS POST PUT)) (container? '(GET HEAD OPTIONS POST PUT DELETE)) (else '(GET HEAD OPTIONS PUT DELETE))))) (unless relevant (let ((final-message (format #f (G_ "the auxiliary resource of type ~s at ~s is absent") (uri->string path-type) (uri->string base-path)))) (raise-exception (make-exception (make-auxiliary-resource-absent base-path path-type) (make-exception-with-message final-message))))) (let ((accept-put (if (or container? path-type) "text/turtle; application/n-quads; application/ld+json" "*/*"))) (values ;; Headers (let ((links (let ((type (make #:target-iri (string-append "http://www.w3.org/ns/ldp#" (if container? "BasicContainer" "Resource")) #:relation-type "type")) (acl (and needs-acl? (make #:target-iri (build-uri 'https #:userinfo (uri-userinfo server-name) #:host (uri-host server-name) #:port (uri-port server-name) #:path (derive-path base-path (string->uri "http://www.w3.org/ns/auth/acl#accessControl"))) #:relation-type "acl"))) (describedby (and needs-meta? (make #:target-iri (build-uri 'https #:userinfo (uri-userinfo server-name) #:host (uri-host server-name) #:port (uri-port server-name) #:path (derive-path base-path (string->uri "https://www.w3.org/ns/iana/link-relations/relation#describedby"))) #:relation-type "describedby"))) (describes (and needs-meta? (make #:target-iri (build-uri 'https #:userinfo (uri-userinfo server-name) #:host (uri-host server-name) #:port (uri-port server-name) #:path base-path) #:relation-type "https://www.w3.org/ns/iana/link-relations/relation#describes"))) (storage (and root? (list (make #:target-iri "http://www.w3.org/ns/pim/space#Storage" #:relation-type "type") (make #:target-iri owner #:relation-type "http://www.w3.org/ns/solid/terms#owner"))))) (append (list type) (if acl (list acl) '()) (if describedby (list describedby) '()) (if describes (list describes) '()) (or storage '()))))) `((link . ,links) (allow . ,allow) (accept-put . ,accept-put) (content-type . (,(if container? 'text/turtle (content-type relevant)))) (etag . (,(etag relevant) . #f)))) ;; Content (if container? (let ((static-graph (parameterize ((p:anonymous-http-request (lambda (uri . args) (values (build-response #:headers `((content-type ,(content-type relevant)))) (static-content relevant))))) (fetch (build-uri 'https #:userinfo (uri-userinfo server-name) #:host (uri-host server-name) #:port (uri-port server-name) #:path path))))) (let ((final-graph (reverse (append (map (lambda (contained-path) (make-rdf-triple (uri->string (build-uri 'https #:userinfo (uri-userinfo server-name) #:host (uri-host server-name) #:port (uri-port server-name) #:path path)) "http://www.w3.org/ns/ldp#contains" (uri->string (build-uri 'https #:userinfo (uri-userinfo server-name) #:host (uri-host server-name) #:port (uri-port server-name) #:path contained-path)))) (contained relevant)) static-graph)))) (rdf->turtle final-graph))) (static-content relevant))))))))))