]> gitweb.factorcode.org Git - factor.git/blob - basis/http/server/static/static.factor
Move call( and execute( to core
[factor.git] / basis / http / server / static / static.factor
1 ! Copyright (C) 2004, 2009 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( filename mime-type -- response ) ]\r
46     [ 2drop <304> ]\r
47     if ;\r
48 \r
49 : serving-path ( filename -- filename )\r
50     [ file-responder get root>> trim-tail-separators "/" ] dip\r
51     "" or trim-head-separators 3append ;\r
52 \r
53 : serve-file ( filename -- response )\r
54     dup mime-type\r
55     dup file-responder get special>> at\r
56     [ call( filename -- response ) ] [ serve-static ] ?if ;\r
57 \r
58 \ serve-file NOTICE add-input-logging\r
59 \r
60 : file>html ( name -- xml )\r
61     dup link-info directory? [ "/" append ] when\r
62     dup [XML <li><a href=<->><-></a></li> XML] ;\r
63 \r
64 : directory>html ( path -- xml )\r
65     [ file-name ]\r
66     [ drop f ]\r
67     [\r
68         [ file-name ] [ [ [ file>html ] map ] with-directory-files ] bi\r
69         [XML <h1><-></h1> <ul><-></ul> XML]\r
70     ] tri\r
71     simple-page ;\r
72 \r
73 : list-directory ( directory -- response )\r
74     file-responder get allow-listings>> [\r
75         directory>html "text/html" <content>\r
76     ] [\r
77         drop <403>\r
78     ] if ;\r
79 \r
80 : find-index ( filename -- path )\r
81     "index.html" append-path dup exists? [ drop f ] unless ;\r
82 \r
83 : serve-directory ( filename -- response )\r
84     url get path>> "/" tail? [\r
85         dup\r
86         find-index [ serve-file ] [ list-directory ] ?if\r
87     ] [\r
88         drop\r
89         url get clone [ "/" append ] change-path <permanent-redirect>\r
90     ] if ;\r
91 \r
92 : serve-object ( filename -- response )\r
93     serving-path dup exists?\r
94     [ dup file-info directory? [ serve-directory ] [ serve-file ] if ]\r
95     [ drop <404> ]\r
96     if ;\r
97 \r
98 M: file-responder call-responder* ( path responder -- response )\r
99     file-responder set\r
100     ".." over member?\r
101     [ drop <400> ] [ "/" join serve-object ] if ;\r
102 \r
103 ! file responder integration\r
104 : enable-fhtml ( responder -- responder )\r
105     [ <fhtml> "text/html" <content> ]\r
106     "application/x-factor-server-page"\r
107     pick special>> set-at ;\r