Cross-Domain Access

WebPivotTable is a client-side web component. When it needs to fetch a data file or connect to an OLAP server hosted on a different domain, the browser's Same-Origin Policy will block the request. This page explains the problem and the proxy solution built into WPT.

Same-Origin Policy

The Same-Origin Policy is a browser security model that restricts scripts on one origin from reading data on another origin. Two URLs share the same origin only when their protocol, host, and port all match.

For example, comparing against http://www.example.com/dir/page.html:

Compared URL Outcome Reason
http://www.example.com/dir/page2.html Same origin Same protocol, host, port
http://www.example.com:81/dir/other.html Blocked Different port
https://www.example.com/dir/other.html Blocked Different protocol
http://en.example.com/dir/other.html Blocked Different host

When WebPivotTable tries to load a CSV or Excel file from another domain, or connect to an OLAP server on a different host/port, the browser blocks the request.

CORS

Cross-Origin Resource Sharing (CORS) lets a server opt-in to cross-origin requests by returning specific HTTP headers. However, you must control the remote server to enable CORS -- which is often not possible with third-party data sources or OLAP servers.


Proxy Solution

The Same-Origin Policy only applies to browsers. A server can fetch any URL without restriction. A proxy accepts requests from the browser, forwards them to the remote server, and returns the response -- bypassing the Same-Origin restriction entirely.

Browser  -->  Proxy (same origin)  -->  Remote Server (different origin)
         <--                        <--

WebPivotTable includes two proxy endpoints to handle the two common cross-origin scenarios:

Proxy Endpoint Purpose
File Proxy POST /api/wpt/file-proxy Fetch remote CSV, Excel, WPT, or web-service data files
XMLA Proxy POST /api/wpt/xmla-proxy Forward SOAP/XML requests to a remote OLAP server

File Proxy (/api/wpt/file-proxy)

Fetches a remote file on behalf of the WPT component.

Request:

POST /api/wpt/file-proxy
X-File-Url: https://example.com/data/sales.csv

The target URL is passed in the X-File-Url header. The proxy fetches that URL server-side and streams the response back with the original Content-Type.

Used by: setWptFromCsvUrl, setWptFromExcelUrl, setWptFromWebService, setWptFromWptUrl, and related APIs when the data file is on a different origin.

XMLA Proxy (/api/wpt/xmla-proxy)

Forwards XMLA (XML for Analysis) SOAP requests to a remote OLAP server.

Request:

POST /api/wpt/xmla-proxy
X-Xmla-Url: https://olap-server.example.com/xmla
Content-Type: text/xml; charset=utf-8

The target XMLA endpoint is passed in the X-Xmla-Url header. The SOAP body is forwarded as-is. The SOAPAction header is also forwarded when present.

Used by: setWptFromOlapCube and OLAP-related operations.

Security

Both proxies include the following safeguards:

  • URL validation -- only http:// and https:// URLs are accepted
  • Rate limiting -- excessive requests from a single client are rejected
  • CORS headers -- responses include Access-Control-Allow-Origin: * so any page embedding WPT can call them

Default Proxy Server

By default, WebPivotTable points to the public proxy hosted at https://new.webpivottable.com:

// Default server options (built into WPT)
{
  server: {
    fileProxyEnabled: 1,
    fileProxy: 'https://new.webpivottable.com/api/wpt/file-proxy',
    xmlaProxyEnabled: 1,
    xmlaProxy: 'https://new.webpivottable.com/api/wpt/xmla-proxy'
  }
}

This means cross-domain loading works out of the box -- no server setup required.

Using Your Own Proxy

If you prefer to route proxy traffic through your own server, you can set up a simple Express server. Here is a complete, ready-to-use example:

1. Install dependencies

npm install express cors request body-parser morgan method-override

2. Create the proxy services (services.js)

"use strict";

var request = require("request");

// Forward XMLA SOAP requests to a remote OLAP server
exports.xmlaProxy = function(req, res) {
  req
    .pipe(
      request(req.headers["x-xmla-url"]).on("error", function(err) {
        res.send(400, err);
      })
    )
    .pipe(res);
};

// Fetch a remote file (CSV, Excel, WPT, etc.) on behalf of the browser
exports.fileProxy = function(req, res) {
  try {
    request
      .get(req.headers["x-file-url"])
      .on("error", function(err) {
        res.send(400, err);
      })
      .pipe(res);
  } catch (error) {
    res.send(500, req.headers["x-file-url"] + " is not available!");
  }
};

3. Create the server (server.js)

var express = require("express"),
  bodyParser = require("body-parser"),
  cors = require("cors"),
  services = require("./services.js"),
  app = express();

app.use(cors());
app.use(bodyParser.json({ limit: "100mb" }));
app.use(bodyParser.urlencoded({ limit: "100mb", extended: true }));

app.post("/wpt/fileProxy", services.fileProxy);
app.post("/wpt/xmlaProxy", services.xmlaProxy);

app.listen(process.env.PORT || 8003);
console.log("Proxy server listening on port " + (process.env.PORT || 8003));

4. Start the server

node server.js

5. Point WPT to your proxy

const wpt = document.getElementById('wpt');

wpt.setOptions({
  server: {
    fileProxy: 'https://your-server.com/wpt/fileProxy',
    xmlaProxy: 'https://your-server.com/wpt/xmlaProxy'
  }
});

You can also disable the proxy entirely if all your data sources are same-origin or CORS-enabled:

wpt.setOptions({
  server: {
    fileProxyEnabled: 0,
    xmlaProxyEnabled: 0
  }
});

See Options for the full list of server-related settings.