X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?a=blobdiff_plain;ds=sidebyside;f=rags.scm;h=177c7b5701d622c99f0c279b4da48af7be7aee1a;hb=fdce37f4be71360bea1ebd0ed864ebffed84265d;hp=69e7ff697ae0d9432673660a8f8a1bcb6c61293c;hpb=2a9ed2e462d2d674248848cd000b29ce50a7c39d;p=rags.git diff --git a/rags.scm b/rags.scm index 69e7ff6..177c7b5 100644 --- a/rags.scm +++ b/rags.scm @@ -1,5 +1,11 @@ ;; The Right-Awful Gemini Server -;; +;; +;; This is a gemini server in the spirit of the +;; scratchy gopher server. Just as for that server, +;; rags uses runtime evaluation of embedded scheme +;; expressions to provide dynamically generated content. +;; +;; See the readme for details. (import (chicken io) (chicken port) @@ -11,7 +17,7 @@ (chicken process) (chicken process-context) (chicken process-context posix) - matchable srfi-13 + matchable srfi-13 srfi-1 uri-common tcp6 openssl) (define-record config @@ -19,7 +25,16 @@ (define file-types '(("gmi" "text/gemini" "charset=utf-8") - ("txt" "text/plain" "charset=utf-8"))) + ("txt" "text/plain" "charset=utf-8") + ("csv" "text/csv" "charset=utf-8") + ("html" "text/html" "charset=utf-8") + ("xml" "text/xml" "charset=utf-8") + ("pdf" "application/pdf") + ("zip" "application/zip") + ("jpg" "image/jpeg") + ("jpeg" "image/jpeg") + ("png" "image/png") + ("mp3" "audio/mpeg"))) (define (process-request config request-line) (let ((uri (uri-normalize-path-segments (absolute-uri request-line)))) @@ -34,18 +49,44 @@ (fail-permanent "Path must be absolute.")) ((not (document-available? config uri)) (fail-permanent "Document not found.")) + ((and (document-path-directory? config uri) + (uri-lacks-trailing-slash? uri)) + (redirect-permanent (uri-with-trailing-slash uri))) + ((document-script? config uri) + (serve-script config uri)) (else (serve-document config uri))))) (define (fail-permanent reason) (print "50 " reason "\r")) +(define (redirect-permanent new-uri) + (print "30 " (uri->string new-uri) "\r")) + +(define (uri-lacks-trailing-slash? uri) + (not (string-null? (last (uri-path uri))))) + +(define (uri-with-trailing-slash uri) + (update-uri uri path: (append (uri-path uri) '("")))) + (define (document-available? config uri) (file-exists? (document-path config uri))) +(define (document-script? config uri) + (let ((path (document-path config uri))) + (and (file-exists? path) + (file-executable? path) + (equal? (pathname-extension path) "scm")))) + +(define (document-path-directory? config uri) + (directory-exists? (document-path-raw config uri))) + +(define (document-path-raw config uri) + (let* ((crumbs (reverse (cons (config-root-dir config) (cdr (uri-path uri)))))) + (make-pathname (reverse (cdr crumbs)) (car crumbs)))) + (define (document-path config uri) - (let* ((crumbs (reverse (cons (config-root-dir config) (cdr (uri-path uri))))) - (path (make-pathname (reverse (cdr crumbs)) (car crumbs)))) + (let* ((path (document-path-raw config uri))) (if (directory-exists? path) (make-pathname path "index.gmi") path))) @@ -58,9 +99,8 @@ (mime-type (cadr mime))) (print "20 " (string-intersperse (cdr mime) ";") "\r") (cond - ((and (equal? mime-type "text/gemini") - (file-executable? path)) - (serve-text-dynamic path)) + ((file-executable? path) + (serve-text-dynamic path)) ; Binary-files can also be generated here, but the source is dynamic text ((string-prefix? "text/" mime-type) (serve-text-plain path)) (else (serve-binary path))))) @@ -107,6 +147,12 @@ (close-output-port out-port)))))) (else (error "Unknown element type.")))) +(define (serve-script config uri) + ;; Scripts are responsible for the entire response, including header + (let ((path (document-path config uri))) + (apply (eval (with-input-from-file path read)) + (list uri)))) + (define (with-current-working-directory directory thunk) (let ((old-wd (current-directory)) (result 'none))