;; webid-oidc, 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 resource content) #:use-module (webid-oidc errors) #:use-module ((webid-oidc stubs) #:prefix stubs:) #:use-module (webid-oidc rdf-index) #:use-module ((webid-oidc refresh-token) #:prefix refresh:) #:use-module (web uri) #: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 (rnrs bytevectors) #:use-module (oop goops) #:export ( with-session )) (define (default-dir) (string-append (refresh:default-dir) "/server")) (define-class () (content-type #:init-keyword #:content-type #:getter content-type) (contained #:init-keyword #:contained #:getter contained) (static-content #:init-keyword #:static-content #:getter static-content)) (define (load-content session dir etag) (let ((first-char (substring etag 0 1)) (rest (substring etag 1))) (call-with-input-file (format #f "~a/content/~a/~a" dir first-char rest) (lambda (port) (let ((properties (read port))) (set-port-encoding! port "ISO-8859-1") (let ((ret (make #:content-type (assq-ref properties 'content-type) #:contained (assq-ref properties 'contained) #:static-content (string->bytevector (get-string-all port) "ISO-8859-1")))) (hash-set! session etag ret) ret)))))) (define (new-content session dir content-type contained static-content) (when (string? static-content) (set! static-content (string->utf8 static-content))) (let ((etag (stubs:random 12))) (let ((first-char (substring etag 0 1)) (rest (substring etag 1))) (stubs:mkdir-p (format #f "~a/content/~a" dir first-char)) (let ((port (open (format #f "~a/content/~a/~a" dir first-char rest) (logior O_WRONLY O_CREAT O_EXCL)))) (write `((content-type . ,content-type) (contained . ,contained)) port) (set-port-encoding! port "ISO-8859-1") (display (bytevector->string static-content "ISO-8859-1") port) (close-port port) (hash-set! session etag (make #:content-type content-type #:contained contained #:static-content static-content)) etag)))) (define (delete-content dir etag) (let ((first-char (substring etag 0 1)) (rest (substring etag 1))) (delete-file (format #f "~a/content/~a/~a" dir first-char rest)))) (define* (with-session f #:key (dir default-dir)) (when (thunk? dir) (set! dir (dir))) (let ((session (make-hash-table))) (define (do-load etag) (or (hash-ref session etag) (load-content session dir etag))) (define (get-content-type etag) (content-type (do-load etag))) (define (get-contained etag) (contained (do-load etag))) (define (get-static-content etag) (static-content (do-load etag))) (define (do-create content-type contained static-content) (new-content session dir content-type contained static-content)) (define (do-delete etag) (delete-content dir etag)) (f get-content-type get-contained get-static-content do-create do-delete)))