summaryrefslogtreecommitdiff
path: root/simple-directory-handler.scm
blob: 47dbea940a9bc07e7e98c74459bf8fec3763f625 (plain)
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
;;;; simple-directory-handler.scm
;
; Copyright (c) 2007-2009, 2012, 2018-2019, Peter Bex
; Copyright (c) 2000-2005, Felix L. Winkelmann
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
;
; 1. Redistributions of source code must retain the above copyright
;    notice, this list of conditions and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright
;    notice, this list of conditions and the following disclaimer in the
;    documentation and/or other materials provided with the distribution.
; 3. Neither the name of the author nor the names of its
;    contributors may be used to endorse or promote products derived
;    from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
; INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
; STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
; OF THE POSSIBILITY OF SUCH DAMAGE.

(module simple-directory-handler
  (simple-directory-handler simple-directory-dotfiles?
                            simple-directory-display-file)

(import scheme (chicken base) (chicken condition) (chicken time posix)
        (chicken file posix) (chicken pathname) (chicken format)
        (chicken file) (only srfi-1 fold) (only (chicken sort) sort)
        intarweb spiffy (only uri-common uri-encode-string char-set:uri-unreserved)
        (only srfi-14 char-set-complement char-set-delete))

(cond-expand
  (chicken-6 (import (scheme base))) ; For make-parameter, which moved from (chicken base)
  (else))

(define (encode-path p)
  (let ((cs (char-set-delete (char-set-complement char-set:uri-unreserved) #\/)))
    (uri-encode-string p cs)))

(define simple-directory-dotfiles? (make-parameter #f))
(define simple-directory-display-file
  (make-parameter
   (lambda (remote-file local-file dir?)
     (sprintf "<tr>
                 <td><a href=\"~a\">~a</a></td>
                 <td>~a</td>
                 <td>~a</td>
               </tr>\n"
	     (htmlize (encode-path remote-file))
	     (string-append (htmlize (pathname-strip-directory remote-file))
			    (if dir? "/" "")) ; a small hint that it's a dir
	     (file-size local-file)
	     (seconds->string (file-modification-time local-file))))))

(define (simple-directory-handler path)
  (let ((str
         (sprintf
             "<!DOCTYPE html PUBLIC
           \"-//W3C//DTD XHTML 1.0 Strict//EN\"
           \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
  <head>
    <title>Index of ~a</title>
  </head>
  <body>
    <h1>Index of ~a:</h1>
    <p><a href=\"~a\">Go to parent directory</a></p>
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Size</th>
          <th>Last modified</th>
        </tr>
      </thead>
      <tbody>~a</tbody>
    </table>
  </body>
</html>"
           path
           path
           (or (pathname-directory path) path)
           (let ((dir (sort (directory (make-pathname (root-path) path)
                                       (simple-directory-dotfiles?))
                            string<?)))
             (fold
              (lambda (file str)
                (let* ((local-file (make-pathname (list (root-path) path)
                                                  file))
                       (remote-file (make-pathname path file))
                       (dir? (directory? local-file)))
                  (condition-case
                      (string-append str ((simple-directory-display-file)
                                          remote-file local-file dir?))
                    ;; Race condition: file might have been deleted or might be
                    ;; otherwise inaccessible (#939; self-referential symlink)
                    ((exn i/o file) str))))
              ""
              dir)))))
    (with-headers `((content-type text/html)
                    (content-length ,(string-length str)))
      (lambda ()
       (write-logged-response)
       (unless (eq? 'HEAD (request-method (current-request)))
         (display str (response-port (current-response))))))))
)