]> gitweb.factorcode.org Git - factor.git/blob - basis/http/server/static/static.factor
Merge branch 'master' of git://factorcode.org/git/factor
[factor.git] / basis / http / server / static / static.factor
1 ! Copyright (C) 2004, 2008 Slava Pestov.\r
2 ! See http://factorcode.org/license.txt for BSD license.\r
3 USING: calendar kernel math math.order math.parser namespaces\r
4 parser sequences strings assocs hashtables debugger mime.types\r
5 sorting logging calendar.format accessors splitting io io.files\r
6 io.files.info io.directories io.pathnames io.encodings.binary\r
7 fry xml.entities destructors urls html xml.syntax\r
8 html.templates.fhtml http http.server http.server.responses\r
9 http.server.redirection xml.writer ;\r
10 IN: http.server.static\r
11 \r
12 TUPLE: file-responder root hook special allow-listings ;\r
13 \r
14 : modified-since ( request -- date )\r
15     "if-modified-since" header ";" split1 drop\r
16     dup [ rfc822>timestamp ] when ;\r
17 \r
18 : modified-since? ( filename -- ? )\r
19     request get modified-since dup [\r
20         [ file-info modified>> ] dip after?\r
21     ] [\r
22         2drop t\r
23     ] if ;\r
24 \r
25 : <file-responder> ( root hook -- responder )\r
26     file-responder new\r
27         swap >>hook\r
28         swap >>root\r
29         H{ } clone >>special ;\r
30 \r
31 : (serve-static) ( path mime-type -- response )\r
32     [\r
33         [ binary <file-reader> &dispose ] dip\r
34         <content> binary >>content-charset\r
35     ]\r
36     [ drop file-info [ size>> ] [ modified>> ] bi ] 2bi\r
37     [ "content-length" set-header ]\r
38     [ "last-modified" set-header ] bi* ;\r
39 \r
40 : <static> ( root -- responder )\r
41     [ (serve-static) ] <file-responder> ;\r
42 \r
43 : serve-static ( filename mime-type -- response )\r
44     over modified-since?\r
45     [ file-responder get hook>> call ] [ 2drop <304> ] if ;\r
46 \r
47 : serving-path ( filename -- filename )\r
48     file-responder get root>> trim-tail-separators\r
49     "/"\r
50     rot "" or trim-head-separators 3append ;\r
51 \r
52 : serve-file ( filename -- response )\r
53     dup mime-type\r
54     dup file-responder get special>> at\r
55     [ call ] [ serve-static ] ?if ;\r
56 \r
57 \ serve-file NOTICE add-input-logging\r
58 \r
59 : file>html ( name -- xml )\r
60     dup link-info directory? [ "/" append ] when\r
61     dup [XML <li><a href=<->><-></a></li> XML] ;\r
62 \r
63 : directory>html ( path -- xml )\r
64     [ file-name ]\r
65     [ drop f ]\r
66     [\r
67         [ file-name ] [ [ [ file>html ] map ] with-directory-files ] bi\r
68         [XML <h1><-></h1> <ul><-></ul> XML]\r
69     ] tri\r
70     simple-page ;\r
71 \r
72 : list-directory ( directory -- response )\r
73     file-responder get allow-listings>> [\r
74         directory>html "text/html" <content>\r
75     ] [\r
76         drop <403>\r
77     ] if ;\r
78 \r
79 : find-index ( filename -- path )\r
80     "index.html" append-path dup exists? [ drop f ] unless ;\r
81 \r
82 : serve-directory ( filename -- response )\r
83     url get path>> "/" tail? [\r
84         dup\r
85         find-index [ serve-file ] [ list-directory ] ?if\r
86     ] [\r
87         drop\r
88         url get clone [ "/" append ] change-path <permanent-redirect>\r
89     ] if ;\r
90 \r
91 : serve-object ( filename -- response )\r
92     serving-path dup exists?\r
93     [ dup file-info directory? [ serve-directory ] [ serve-file ] if ]\r
94     [ drop <404> ]\r
95     if ;\r
96 \r
97 M: file-responder call-responder* ( path responder -- response )\r
98     file-responder set\r
99     ".." over member?\r
100     [ drop <400> ] [ "/" join serve-object ] if ;\r
101 \r
102 ! file responder integration\r
103 : enable-fhtml ( responder -- responder )\r
104     [ <fhtml> "text/html" <content> ]\r
105     "application/x-factor-server-page"\r
106     pick special>> set-at ;\r