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()}
};