Skip to content

Hardcoded crossOriginPolicy:Anonymous breaks manifests whose image host lacks CORS headers #564

Description

@tacman

Summary

viewer-element.ts hardcodes OpenSeadragon's crossOriginPolicy: "Anonymous" and loadTilesWithAjax: true with no way for a host page to override it. Any manifest whose image server doesn't send Access-Control-Allow-Origin (very common — many museum/library CDNs don't) fails to render at all, even though the same image loads fine with plain <img>-style loading (no CORS needed for basic display).

https://github.com/DDMAL/diva.js/blob/v7.3.1/src/viewer-element.ts#L133

const options = {
    element : this.container,
    ...
    crossOriginPolicy : "Anonymous",
    loadTilesWithAjax : true,
    ajaxWithCredentials : false,
    ...
} as any;
this.viewer = OpenSeadragon(options);

Reproduction

Manifest: https://openaccess-cdn.clevelandart.org/2022.346/2022.346_web.jpg (referenced, no service, plain IIIF v3 Presentation manifest built from Cleveland Museum's Open Access API). The image response has no access-control-allow-origin header at all (verified via curl -I).

Loading this manifest in diva 7.3.1 results in a blank viewport and a flood of console errors:

Access to image at 'https://openaccess-cdn.clevelandart.org/2022.346/2022.346_web.jpg' from origin '...' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Confirmed with an isolated test — same OpenSeadragon version, same image URL, only the tile-source options differ:

// diva's hardcoded settings -> fails
OpenSeadragon({ element, crossOriginPolicy: 'Anonymous', loadTilesWithAjax: true, tileSources: [{ type: 'image', url }] })
// => open-failed: "Error loading image at ..."

// without CORS mode -> succeeds
OpenSeadragon({ element, crossOriginPolicy: false, loadTilesWithAjax: false, tileSources: [{ type: 'image', url }] })
// => opens, fullyLoaded: true

Related history

#489 reported the same class of problem against the old (pre-rewrite) codebase, where imageCrossOrigin: null was available as a workaround/setting. The v7 rewrite appears to have dropped that configurability entirely — there's no equivalent option exposed today, so this isn't just a missing default, it's a missing escape hatch.

Secondary issue found while investigating

With the failing manifest above, diva enters what looks like an unbounded retry loop — DevTools network log showed 75,000+ repeated GET requests to the same failing image URL within about a minute, with no backoff or retry cap. Might be worth its own issue, but flagging here since it was found in the same repro.

Suggested fix

Either:

  • Expose crossOriginPolicy / loadTilesWithAjax as configurable settings (restoring rough parity with the old imageCrossOrigin option), or
  • Default to crossOriginPolicy: false for plain (non-IIIF-Image-API) static image bodies, since canvas pixel-level access isn't needed for basic display — only tile-pyramid/Image-API sources arguably benefit from AJAX-loaded, CORS-mode tiles.

Environment

  • diva.js 7.3.1 (npm)
  • Chromium (via Playwright), also reproduces in this project's own browser testing

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions