XQuery/Setting HTTP Headers
< XQuery
Motivation
editYou want to put information in your outgoing HTTP headers to control aspects such as web caching and ETAGS.
Sample Module
editThe following module was provided by Thomas White.
File tw_stream-binary-cached.xql
xquery version "1.0" encoding "UTF-8";
module namespace cached-binary = "http://www.thomas-white.net/xqm/stream-binary-cached.1.0" ;
declare default function namespace "http://www.w3.org/2005/xpath-functions";
import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace cache = "http://exist-db.org/xquery/cache";
import module namespace datetime = "http://exist-db.org/xquery/datetime";
import module namespace util = "http://exist-db.org/xquery/util";
declare option exist:serialize "method=xml media-type=text/xml";
declare function cached-binary:eTag( $pathToBinaryResource as xs:string, $last-modified as xs:dateTime, $domain-tag as xs:string ) as xs:string{
concat( $domain-tag, '-',
util:document-id( $pathToBinaryResource ) ,'-',
fn:translate( fn:substring($last-modified,1,19),':-T' , '') )
};
declare function cached-binary:eTag-from-uri( $pathToBinaryResource as xs:string, $domain-tag as xs:string ) as xs:string{
cached-binary:eTag( $pathToBinaryResource,
xdb:last-modified( util:collection-name( $pathToBinaryResource ), util:document-name( $pathToBinaryResource )),
$domain-tag)
};
declare function cached-binary:stream-binary-with-cache-headers(
$original-path as xs:string?,
$pathToBinaryResource as xs:string,
$expiresAfter as xs:dayTimeDuration?,
$must-revalidate as xs:boolean,
$doNotCache as xs:string,
$domain as xs:string?
) {
if( fn:string-length($pathToBinaryResource) = 0 or not( util:binary-doc-available( $pathToBinaryResource )) ) then (
response:set-status-code( 404 ),
concat( $original-path, ' ( ', $pathToBinaryResource, ' ) not found!') (: ($original-path, $pathToBinaryResource)[1] :)
) else (
let $coll := util:collection-name( $pathToBinaryResource )
let $file := util:document-name( $pathToBinaryResource )
let $last-modified := xdb:last-modified( $coll, $file)
let $ETag := cached-binary:eTag( $pathToBinaryResource, $last-modified, $domain )
let $if-modified-since := request:get-header('If-Modified-Since')
let $expire-after := if( empty($expiresAfter) ) then xs:dayTimeDuration( "P365D" ) else $expiresAfter (: 365 Day expiry period :)
let $content-type:= (
util:declare-option('exist:serialize', concat("media-type=", xdb:get-mime-type( xs:anyURI( $pathToBinaryResource) )) ),
response:set-header( "Pragma", 'o' )
)
return if( not($doNotCache = 'true') and (
( request:get-header('If-None-Match') = $ETag ) or (: ETag :)
(fn:string-length($if-modified-since) > 0 and datetime:parse-dateTime( $if-modified-since, 'EEE, d MMM yyyy HH:mm:ss Z' ) <= $last-modified )
)) then (
response:set-status-code( 304 ),
response:set-header( "Cache-Control", concat('public, max-age=', $expire-after div xs:dayTimeDuration('PT1S') )) (: 24h=86,400 , must-revalidate :)
) else (
let $maxAge := $expire-after div xs:dayTimeDuration('PT1S')
let $headers := (
response:set-header( "ETag", $ETag ),
response:set-header( "Last-Modified", datetime:format-dateTime( $last-modified, 'EEE, d MMM yyyy HH:mm:ss Z' )),
response:set-header( "Expires", datetime:format-dateTime( dateTime(current-date(), util:system-time()) + $expire-after, 'EEE, d MMM yyyy HH:mm:ss Z' )),
if( $doNotCache = 'true' ) then (
response:set-header( "Cache-Control", 'no-cache, no-store, max-age=0, must-revalidate' ),
response:set-header( "X-Content-Type-Options", 'nosniff' )
)else
response:set-header( "Cache-Control", concat( 'public, max-age=', $maxAge, if( $must-revalidate ) then ', must-revalidate' else '' ))
)
return response:stream-binary(
util:binary-doc( xs:anyURI($pathToBinaryResource ) ),
xdb:get-mime-type( xs:anyURI( $pathToBinaryResource) ),
xs:anyURI( ($original-path, $pathToBinaryResource)[1] )
)
)
)
};
(:
HTTP/1.1 200 OK
Date: Fri, 30 Oct 1998 13:19:41 GMT
Server: Apache/1.3.3 (Unix)
Cache-Control: max-age=3600, must-revalidate
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT
ETag: "3e86-410-3596fbbc"
Content-Length: 1040
Content-Type: text/html
Cache-Control: max-age=3600, must-revalidate
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT
ETag: "3e86-410-3596fbbc"
Cache-Control: public, max-age=1728000
Expires: Thu, 06 Aug 2009 10:04:13 GMT
Date: Fri, 17 Jul 2009 10:04:13 GMT
Content-Type: text/javascript; charset=UTF-8
ETag: "ih2h6n8r44hc"
Last-Modified: Fri, 05 Sep 2003 02:11:15 GMT
X-Content-Type-Options: nosniff
:)
xquery version "1.0" encoding "UTF-8";
declare default function namespace "http://www.w3.org/2005/xpath-functions";
import module namespace request = "http://exist-db.org/xquery/request";
import module namespace cached-binary = "http://www.thomas-white.net/xqm/stream-binary-cached.1.0" at "tw_stream-binary-cached.xql";
cached-binary:stream-binary-with-cache-headers(
request:get-parameter("url", ()),
request:get-parameter("uri", 'no-uri'),
xs:dayTimeDuration(request:get-parameter("expire", 'P30D')),
xs:boolean(request:get-parameter("must-revalidate", 'false') = 'true'),
request:get-parameter("doNotCache", ''),
request:get-parameter("domain", '')
)