View source with formatted comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2011, VU University Amsterdam
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   34
   35:- module(http_files,
   36          [ http_reply_from_files/3     % +Dir, +Options, +Request
   37          ]).   38:- use_module(library(http/http_dispatch)).   39:- use_module(library(http/http_dirindex)).   40:- use_module(library(filesex)).   41:- use_module(library(lists)).   42:- use_module(library(option)).   43
   44:- predicate_options(http_reply_from_files/3, 2, [indexes(list(atom))]).   45
   46/** <module> Serve plain files from a hierarchy
   47
   48Although the SWI-Prolog Web Server is intended to serve documents that
   49are computed dynamically, serving plain files is sometimes necessary.
   50This small module combines the functionality of http_reply_file/3 and
   51http_reply_dirindex/3 to act as a simple web-server.  Such a server
   52can be created using the following code sample, which starts a server
   53at port 8080 that serves files from the current directory ('.').  Note
   54that the handler needs a =prefix= option to specify that it must
   55handle all paths that begin with the registed location of the handler.
   56
   57  ==
   58  :- use_module(library(http/thread_httpd)).
   59  :- use_module(library(http/http_dispatch)).
   60
   61  :- http_handler(root(.), http_reply_from_files('.', []), [prefix]).
   62
   63  :- initialization
   64        http_server(http_dispatch, [port(8080)]).
   65  ==
   66
   67@see    pwp_handler/2 provides similar facilities, where .pwp files
   68        can be used to add dynamic behaviour.
   69*/
   70
   71
   72%!  http_reply_from_files(+Dir, +Options, +Request)
   73%
   74%   HTTP handler that serves files  from   the  directory  Dir. This
   75%   handler uses http_reply_file/3 to  reply   plain  files.  If the
   76%   request resolves to a directory, it uses the option =indexes= to
   77%   locate an index file (see   below) or uses http_reply_dirindex/3
   78%   to create a listing of the directory.
   79%
   80%   Options:
   81%
   82%     * indexes(+List)
   83%     List of files tried to find an index for a directory.  The
   84%     default is ['index.html'].
   85%
   86%   Note that this handler must be tagged as a =prefix= handler (see
   87%   http_handler/3 and module introduction). This  also implies that
   88%   it is possible to  override  more   specific  locations  in  the
   89%   hierarchy using http_handler/3 with a longer path-specifier.
   90%
   91%   @param  Dir is either a directory or an path-specification as
   92%           used by absolute_file_name/3.  This option provides
   93%           great flexibility in (re-)locating the physical files
   94%           and allows merging the files of multiple physical
   95%           locations into one web-hierarchy by using multiple
   96%           user:file_search_path/2 clauses that define the same
   97%           alias.
   98%   @see    The hookable predicate file_mime_type/2 is used to
   99%           determine the =|Content-type|= from the file name.
  100
  101http_reply_from_files(Dir, Options, Request) :-
  102    (   memberchk(path_info(PathInfo), Request)
  103    ->  true
  104    ;   PathInfo = ''
  105    ),
  106    http_safe_file(PathInfo, []),
  107    locate_file(Dir, PathInfo, Path, IsFile, Options),
  108    (   IsFile == true
  109    ->  http_reply_file(Path, [unsafe(true)], Request)
  110    ;   http_reply_dirindex(Path, [unsafe(true)], Request)
  111    ).
  112
  113locate_file(Dir, PathInfo, Result, IsFile, Options) :-
  114    absolute_file_name(Dir, DirPath,
  115                       [ file_type(directory),
  116                         access(read),
  117                         solutions(all)
  118                       ]),
  119    directory_file_path(DirPath, PathInfo, Path),
  120    (   exists_file(Path)
  121    ->  IsFile = true,
  122        Result = Path
  123    ;   exists_directory(Path),
  124        (   option(indexes(Indexes), Options, ['index.html']),
  125            member(Index, Indexes),
  126            directory_file_path(Path, Index, IndexFile),
  127            exists_file(IndexFile)
  128        ->  Result = IndexFile,
  129            IsFile = true
  130        ;   Result = Path,
  131            IsFile = false
  132        )
  133    )