XQuery/Setting HTTP Headers
Appearance
< XQuery
Motivation
[edit | edit source]You want to put information in your outgoing HTTP headers to control aspects such as web caching and ETAGS.
Sample Module
[edit | edit source]The 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", '')
)