! Copyright (C) 2004, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: calendar html io io.files kernel math math.parser http http.server namespaces parser sequences strings assocs hashtables debugger http.mime sorting html.elements logging calendar.format accessors io.encodings.binary fry ; IN: http.server.static ! special maps mime types to quots with effect ( path -- ) TUPLE: file-responder root hook special ; : file-http-date ( filename -- string ) file-info modified>> timestamp>http-string ; : last-modified-matches? ( filename -- ? ) file-http-date dup [ request get "if-modified-since" header = ] when ; : <304> ( -- response ) 304 "Not modified" ; : ( root hook -- responder ) H{ } clone file-responder boa ; : ( root -- responder ) [ swap [ file-info size>> "content-length" set-header ] [ file-http-date "last-modified" set-header ] [ '[ , binary stdio get stream-copy ] >>body ] tri ] ; : serve-static ( filename mime-type -- response ) over last-modified-matches? [ 2drop <304> ] [ file-responder get hook>> call ] if ; : serving-path ( filename -- filename ) file-responder get root>> right-trim-separators "/" rot "" or left-trim-separators 3append ; : serve-file ( filename -- response ) dup mime-type dup file-responder get special>> at [ call ] [ serve-static ] ?if ; \ serve-file NOTICE add-input-logging : file. ( name dirp -- ) [ "/" append ] when dup write ; : directory. ( path -- ) dup file-name [ [

file-name write

] [
    directory sort-keys [
  • file.
  • ] assoc-each
] bi ] simple-html-document ; : list-directory ( directory -- response ) "text/html" swap '[ , directory. ] >>body ; : find-index ( filename -- path ) "index.html" append-path dup exists? [ drop f ] unless ; : serve-directory ( filename -- response ) request get path>> "/" tail? [ dup find-index [ serve-file ] [ list-directory ] ?if ] [ drop request get path>> "/" append f ] if ; : serve-object ( filename -- response ) serving-path dup exists? [ dup directory? [ serve-directory ] [ serve-file ] if ] [ drop <404> ] if ; M: file-responder call-responder* ( path responder -- response ) file-responder set ".." over member? [ drop <400> ] [ "/" join serve-object ] if ;