xquery version "3.1";
module namespace api = "http://acdh.oeaw.ac.at/vicav/api/http";
import module namespace request = "http://exquery.org/ns/request";
import module namespace jobs = "http://basex.org/modules/jobs";
import module namespace l = "http://basex.org/modules/admin";
import module namespace rest = "http://exquery.org/ns/restxq";
declare function api:get-base-uri-public() as xs:string {
let $forwarded-hostname := if (contains(request:header('X-Forwarded-Host'), ','))
then substring-before(request:header('X-Forwarded-Host'), ',')
else request:header('X-Forwarded-Host'),
$urlScheme := if ((lower-case(request:header('X-Forwarded-Proto')) = 'https') or
(lower-case(request:header('Front-End-Https')) = 'on')) then 'https' else 'http',
$port := if ($urlScheme eq 'http' and request:port() ne 80) then ':'||request:port()
else if ($urlScheme eq 'https' and not(request:port() eq 80 or request:port() eq 443)) then ':'||request:port()
else '',
(: FIXME: this is to naive. Works for ProxyPass / to /exist/apps/cr-xq-mets/project
but probably not for /x/y/z/ to /exist/apps/cr-xq-mets/project. Especially check the get module. :)
$xForwardBasedPath := replace((request:header('X-Forwarded-Request-Uri'), request:path())[1], '^([^?]*)(\?.*)$', '$1')
return $urlScheme||'://'||($forwarded-hostname, request:hostname())[1]||$port||$xForwardBasedPath
};
(:~
: Returns a html or related file.
: @param $file file or unknown path
: @return rest response and binary file
:)
declare
%rest:path("vicav/{$file=[^/]+}")
function api:file($file as xs:string) as item()+ {
let $path := api:base-dir()|| $file
return if (file:exists($path)) then
if (matches($file, '\.(htm|html|pdf|m4a|js|docx|map|css|png|gif|jpg|jpeg|woff|woff2|svg|ttf|mp4)$', 'i')) then
let $bin := file:read-binary($path)
, $hash := xs:string(xs:hexBinary(hash:md5($bin)))
, $hashBrowser := request:header('If-None-Match', '')
return if ($hash = $hashBrowser) then
web:response-header(map{}, map{}, map{'status': 304, 'message': 'Not Modified'})
else (
web:response-header(map { 'media-type': web:content-type($path),
'method': 'basex',
'binary': 'yes' },
map { 'X-UA-Compatible': 'IE=11'
, 'Cache-Control': 'max-age=3600,public'
, 'ETag': $hash }),
$bin
) else api:forbidden-file($file)
else
(
web:response-header(map{'media-type': 'text/html',
'method': 'html'},
map{'Content-Language': 'en',
'X-UA-Compatible': 'IE=11'},
map{'status': 404, 'message':$file||' was not found'}),
{$file||' was not found'}
{$file||' was not found'}
)
};
declare
%rest:path("vicav/js/{$file=.+}")
function api:bower_components-file($file as xs:string) as item()+ {
api:file('js/'||$file)
};
declare
%rest:path("vicav/downloads/{$file=.+}")
function api:docs-file($file as xs:string) as item()+ {
api:file('downloads/'||$file)
};
declare
%rest:path("vicav/docs/{$file=.+}")
function api:pdf-file($file as xs:string) as item()+ {
api:file('docs/'||$file)
};
declare
%rest:path("vicav/css/{$file=.+}")
function api:css-file($file as xs:string) as item()+ {
api:file('css/'||$file)
};
declare
%rest:path("vicav/vendor/{$file=.+}")
function api:vendor-file($file as xs:string) as item()+ {
api:file('vendor/'||$file)
};
declare
%rest:path("vicav/images/{$file=.+}")
function api:images-file($file as xs:string) as item()+ {
api:file('images/'||$file)
};
declare
%rest:path("vicav/fonts/{$file=.+}")
function api:fonts-file($file as xs:string) as item()+ {
api:file('fonts/'||$file)
};
declare
%rest:path("vicav/favicons/{$file=.+}")
function api:favicons-file($file as xs:string) as item()+ {
api:file('favicons/'||$file)
};
declare %private function api:base-dir() as xs:string {
file:base-dir()
(: if this is in a subdirectory say "responses"
replace(file:base-dir(), '^(.+)responses.*$', '$1') :)
};
(:~
: Returns index.html on /.
: @param $file file or unknown path
: @return rest response and binary file
:)
declare
%rest:path("vicav")
function api:index-file() as item()+ {
let $index-html := api:base-dir()||'index.html',
$index-htm := api:base-dir()||'index.htm',
$uri := rest:uri(),
(: $log := l:write-log('api:index-file() $uri := '||$uri||' base-uri-public := '||api:get-base-uri-public(), 'DEBUG'),:)
$absolute-prefix := if (matches(api:get-base-uri-public(), '/$')) then () else api:get-base-uri-public()||'/'
return if (exists($absolute-prefix)) then
else if (file:exists($index-html)) then
index.html
else if (file:exists($index-htm)) then
index.htm
else api:forbidden-file($index-html)
};
(:~
: Return 403 on all other (forbidden files).
: @param $file file or unknown path
: @return rest response and binary file
:)
declare
%private
function api:forbidden-file($file as xs:string) as item()+ {
,
{$file||' forbidden'}
{$file||' forbidden'}
};
declare
%rest:path("vicav/test-error.xqm")
function api:test-error() as item()+ {
api:test-error('api:test-error')
};
declare
%rest:path("vicav/test-error.xqm/{$error-qname}")
function api:test-error($error-qname as xs:string) as item()+ {
error(xs:QName($error-qname))
};
declare
%rest:path("vicav/runtime")
function api:runtime-info() as item()+ {
let $runtime-info := db:system(),
$xslt-runtime-info := xslt:transform(<_/>,
<_>)/*
return
Runtime info
Runtime info
{for $item in $runtime-info/*:generalinformation/*
return
| {$item/local-name()} |
{$item} |
}
| {$xslt-runtime-info/*:product-name/text()} |
{$xslt-runtime-info/*:product-version/text()} |
};