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) 2008-2014, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(http_path, 37 [ http_absolute_uri/2, % +Spec, -URI 38 http_absolute_location/3, % +Spec, -Path, +Options 39 http_clean_location_cache/0 40 ]). 41:- use_module(library(lists)). 42:- use_module(library(error)). 43:- use_module(library(apply)). 44:- use_module(library(debug)). 45:- use_module(library(option)). 46:- use_module(library(settings)). 47:- use_module(library(broadcast)). 48:- use_module(library(uri)). 49:- use_module(library(http/http_host)). 50:- use_module(library(http/http_wrapper)). 51 52 53:- predicate_options(http_absolute_location/3, 3, [relative_to(atom)]).
98:- setting(http:prefix, atom, '',
99 'Prefix for all locations of this server').
/
. Options currently only supports the
priority of the path. If http:location/3 returns multiple
solutions the one with the highest priority is selected. The
default priority is 0.
This library provides a default for the abstract location
root
. This defaults to the setting http:prefix or, when not
available to the path /
. It is adviced to define all
locations (ultimately) relative to root
. For example, use
root('home.html')
rather than '/home.html'
.
119:- multifile 120 http:location/3. % Alias, Expansion, Options 121:- dynamic 122 http:location/3. % Alias, Expansion, Options 123 124httplocation(root, Root, [priority(-100)]) :- 125 ( setting(http:prefix, Prefix), 126 Prefix \== '' 127 -> Root = Prefix 128 ; Root = (/) 129 ).
http://
) URI for
the abstract specification Spec. Use http_absolute_location/3 to
create references to locations on the same server.
140http_absolute_uri(Spec, URI) :-
141 http_current_host(_Request, Host, Port,
142 [ global(true)
143 ]),
144 http_absolute_location(Spec, Path, []),
145 uri_authority_data(host, AuthC, Host),
146 ( Port == 80 % HTTP scheme
147 -> true
148 ; uri_authority_data(port, AuthC, Port)
149 ),
150 uri_authority_components(Authority, AuthC),
151 uri_data(path, Components, Path),
152 uri_data(scheme, Components, http),
153 uri_data(authority, Components, Authority),
154 uri_components(URI, Components).
169:- dynamic 170 location_cache/3. 171 172http_absolute_location(Spec, Path, Options) :- 173 must_be(ground, Spec), 174 option(relative_to(Base), Options, /), 175 absolute_location(Spec, Base, Path, Options), 176 debug(http_path, '~q (~q) --> ~q', [Spec, Base, Path]). 177 178absolute_location(Spec, Base, Path, _Options) :- 179 location_cache(Spec, Base, Cache), 180 !, 181 Path = Cache. 182absolute_location(Spec, Base, Path, Options) :- 183 expand_location(Spec, Base, L, Options), 184 assert(location_cache(Spec, Base, L)), 185 Path = L. 186 187expand_location(Spec, Base, Path, _Options) :- 188 atomic(Spec), 189 !, 190 ( uri_components(Spec, Components), 191 uri_data(scheme, Components, Scheme), 192 atom(Scheme) 193 -> Path = Spec 194 ; relative_to(Base, Spec, Path) 195 ). 196expand_location(Spec, _Base, Path, Options) :- 197 Spec =.. [Alias, Sub], 198 http_location_path(Alias, Parent), 199 absolute_location(Parent, /, ParentLocation, Options), 200 phrase(path_list(Sub), List), 201 atomic_list_concat(List, /, SubAtom), 202 ( ParentLocation == '' 203 -> Path = SubAtom 204 ; sub_atom(ParentLocation, _, _, 0, /) 205 -> atom_concat(ParentLocation, SubAtom, Path) 206 ; atomic_list_concat([ParentLocation, SubAtom], /, Path) 207 ).
219http_location_path(Alias, Path) :-
220 findall(P-L, http_location_path(Alias, L, P), Pairs),
221 sort(Pairs, Sorted0),
222 reverse(Sorted0, Result),
223 ( Result = [_-One]
224 -> Path = One
225 ; Result == []
226 -> existence_error(http_alias, Alias)
227 ; Result = [P-Best,P2-_|_],
228 P \== P2
229 -> Path = Best
230 ; Result = [_-First|_],
231 pairs_values(Result, Paths),
232 print_message(warning, http(ambiguous_location(Alias, Paths))),
233 Path = First
234 ).
241http_location_path(Alias, Path, Priority) :- 242 http:location(Alias, Path, Options), 243 option(priority(Priority), Options, 0). 244http_location_path(prefix, Path, 0) :- 245 ( catch(setting(http:prefix, Prefix), _, fail), 246 Prefix \== '' 247 -> ( sub_atom(Prefix, 0, _, _, /) 248 -> Path = Prefix 249 ; atom_concat(/, Prefix, Path) 250 ) 251 ; Path = / 252 ).
260relative_to(/, Path, Path) :- !. 261relative_to(_Base, Path, Path) :- 262 sub_atom(Path, 0, _, _, /), 263 !. 264relative_to(Base, Local, Path) :- 265 sub_atom(Base, 0, _, _, /), % file version 266 !, 267 path_segments(Base, BaseSegments), 268 append(BaseDir, [_], BaseSegments) -> 269 path_segments(Local, LocalSegments), 270 append(BaseDir, LocalSegments, Segments0), 271 clean_segments(Segments0, Segments), 272 path_segments(Path, Segments). 273relative_to(Base, Local, Global) :- 274 uri_normalized(Local, Base, Global). 275 276path_segments(Path, Segments) :- 277 atomic_list_concat(Segments, /, Path).
284clean_segments([''|T0], [''|T]) :- 285 !, 286 exclude(empty_segment, T0, T1), 287 clean_parent_segments(T1, T). 288clean_segments(T0, T) :- 289 exclude(empty_segment, T0, T1), 290 clean_parent_segments(T1, T). 291 292clean_parent_segments([], []). 293clean_parent_segments([..|T0], T) :- 294 !, 295 clean_parent_segments(T0, T). 296clean_parent_segments([_,..|T0], T) :- 297 !, 298 clean_parent_segments(T0, T). 299clean_parent_segments([H|T0], [H|T]) :- 300 clean_parent_segments(T0, T). 301 302empty_segment(''). 303empty_segment('.').
313path_list(Var) --> 314 { var(Var), 315 !, 316 instantiation_error(Var) 317 }. 318path_list(A/B) --> 319 !, 320 path_list(A), 321 path_list(B). 322path_list(.) --> 323 !, 324 []. 325path_list(A) --> 326 { must_be(atomic, A) }, 327 [A]. 328 329 330 /******************************* 331 * MESSAGES * 332 *******************************/ 333 334:- multifile 335 prolog:message/3. 336 337prologmessage(http(ambiguous_location(Spec, Paths))) --> 338 [ 'http_absolute_location/2: ambiguous specification: ~q: ~p'- 339 [Spec, Paths] 340 ]. 341 342 343 /******************************* 344 * CACHE CLEANUP * 345 *******************************/
354http_clean_location_cache :- 355 retractall(location_cache(_,_,_)). 356 357:- listen(settings(changed(http:prefix, _, _)), 358 http_clean_location_cache). 359 360:- multifile 361 user:message_hook/3. 362:- dynamic 363 user:message_hook/3. 364 365user:message_hook(make(done(Reload)), _Level, _Lines) :- 366 Reload \== [], 367 http_clean_location_cache, 368 fail
Abstract specification of HTTP server locations
This module provides an abstract specification of HTTP server locations that is inspired on absolute_file_name/3. The specification is done by adding rules to the dynamic multifile predicate http:location/3. The speficiation is very similar to file_search_path/2, but takes an additional argument with options. Currently only one option is defined:
The default priority is 0. Note however that notably libraries may decide to provide a fall-back using a negative priority. We suggest -100 for such cases.
This library predefines a single location at priority -100:
http:prefix
To serve additional resource files such as CSS, JavaScript and icons, see
library(http/http_server_files)
.Here is an example that binds
/login
to login/1. The user can reuse this application while moving all locations using a new rule for the admin location with the option[priority(10)]
.*/