Documentation
Advanced Usage
Request Response Functions

Request/Response Functions

The IIIF service can be heavily customized through the use of CloudFront Functions (opens in a new tab) or Lambda@Edge Functions (opens in a new tab) attached to a CloudFront distribution in front of the service. It's important to understand the four stages of CloudFront processing in order to know where a given type of customization belongs.

  • A viewer-request function will be called on every request, cached or not. This is the appropriate place to attach a function that performs authorization, authentication, or anything else whose result should not be cached.
  • An origin-request function will only be called when CloudFront refreshes the content from the origin (e.g., the IIIF server). It's the appropriate place to attach a function that should be cached, such as S3 file resolution or the retrieval of image dimensions.
  • Similarly, the origin-response and viewer-response functions are called after the IIIF server returns its response and before CloudFront passes it on to the viewer, respectively. They can be used to alter the response in a way that is either cached or ephemeral.

Examples

These examples use CloudFront Functions. Lambda@Edge functions are slightly more complicated in terms of the event structure but the basic idea is the same.

Simple Authorization
function handler(event) {
    if (notAuthorized) { // based on something in the event.request
       return {
         statusCode: 403,
         statusDescription: 'Unauthorized'
       };
    };
    return event.request;
}
Custom File Location / Image Dimensions
function handler(event) {
  var request = event.request;
  request.headers['x-preflight-location'] = [{value: 's3://image-bucket/path/to/correct/image.tif'}];
  request.headers['x-preflight-dimensions'] = [{value: JSON.stringify({ width: 640, height: 480, pages: 3 })}];
  return request;
}

The x-preflight-dimensions header should be a JSON object including some or all of the following properties:

  • Basic properties (required):
    • width: the width in pixels of the largest representation of the entire image
    • height: the height in pixels of the largest representation of the entire image
  • Multi-resolution properties (at least one is required):
    • sizes: an array of [{width, height}] listing the size in pixels of each resolution included in the pyramidal image
    • pages: the number of resolutions contained in the pyramidal image (or 1 if the image isn't pyramidal)
  • Optional properties:
    • tileWidth: the tile width used when generating the tiled pyramidal image
    • tileHeight: the tile height used when generating the tiled pyramidal image

For example, the following dimension values would all describe the same pyramidal image:

  • { width: 1024, height: 768, sizes: [{ width: 1024, height: 768 }, { width: 512, height: 384 }, { width: 256, height: 192 }] }
  • { width: 1024, height: 768, pages: 3 }

When responding to an Image Information Document (info.json) document request, if tileWidth is not present, the image will be probed to determine the correct values for tileWidth and tileHeight. If tileWidth is present but null, the tiles property will not be included in the output.

💡

If you plan to use CloudFront functions to add either of the above x-preflight- headers to incoming requests, you must set the value of the Preflight parameter to true when deploying serverless-iiif. The function will only look for the preflight headers if this environment variable is true. This prevents requests from including those headers directly if no preflight function is present. If you do use a preflight function, make sure it strips out any x-preflight-location and x-preflight-dimensions headers that it doesn't set itself.