@esri/arcgis-rest-request
Version:
Common methods and utilities for @esri/arcgis-rest-js packages.
157 lines • 6.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNoCorsRequestRequired = exports.isNoCorsDomain = exports.registerNoCorsDomains = exports.getRegisteredNoCorsDomains = exports.sendNoCorsRequest = void 0;
const requestConfig_js_1 = require("../requestConfig.js");
/**
* Send a no-cors request to the passed uri. This is used to pick up
* a cookie from a 3rd party server to meet a requirement of some authentication
* flows.
* @param url
* @returns
*/
function sendNoCorsRequest(url) {
// drop any query params, other than f=json
const urlObj = new URL(url);
url = urlObj.origin + urlObj.pathname;
if (urlObj.search.includes("f=json")) {
url += "?f=json";
}
const origin = urlObj.origin;
// If we have already sent a no-cors request to this url, return the promise
// so we don't send multiple requests
if (requestConfig_js_1.requestConfig.pendingNoCorsRequests[origin]) {
return requestConfig_js_1.requestConfig.pendingNoCorsRequests[origin];
}
// Make the request and add to the cache
requestConfig_js_1.requestConfig.pendingNoCorsRequests[origin] = fetch(url, {
mode: "no-cors",
credentials: "include",
cache: "no-store"
})
.then((response) => {
// Add to the list of cross-origin no-cors domains
// if the domain is not already in the list
if (requestConfig_js_1.requestConfig.noCorsDomains.indexOf(origin) === -1) {
requestConfig_js_1.requestConfig.noCorsDomains.push(origin);
}
// Hold the timestamp of this request so we can decide when to
// send another request to this domain
requestConfig_js_1.requestConfig.crossOriginNoCorsDomains[origin.toLowerCase()] = Date.now();
// Remove the pending request from the cache
delete requestConfig_js_1.requestConfig.pendingNoCorsRequests[origin];
// Due to limitations of fetchMock at the version of the tooling
// in this project, we can't mock the response type of a no-cors request
// and thus we can't test this. So we are going to comment this out
// and leave it in place for now. If we need to test this, we can
// update the tooling to a version that supports this. Also
// JS SDK does not do this check, so we are going to leave it out for now.
// ================================================================
// no-cors requests are opaque to javascript
// and thus will always return a response with a type of "opaque"
// if (response.type === "opaque") {
// return Promise.resolve();
// } else {
// // Not sure if this is possible, but since we have a check above
// // lets handle the else case
// return Promise.reject(
// new Error(`no-cors request to ${origin} not opaque`)
// );
// }
// ================================================================
})
.catch((e) => {
// Not sure this is necessary, but if the request fails
// we should remove it from the pending requests
// and return a rejected promise with some information
delete requestConfig_js_1.requestConfig.pendingNoCorsRequests[origin];
return Promise.reject(new Error(`no-cors request to ${origin} failed`));
});
// return the promise
return requestConfig_js_1.requestConfig.pendingNoCorsRequests[origin];
}
exports.sendNoCorsRequest = sendNoCorsRequest;
/**
* Allow us to get the no-cors domains that are registered
* so we can pass them into the identity manager
* @returns
*/
function getRegisteredNoCorsDomains() {
// return the no-cors domains
return requestConfig_js_1.requestConfig.noCorsDomains;
}
exports.getRegisteredNoCorsDomains = getRegisteredNoCorsDomains;
/**
* Register the domains that are allowed to be used in no-cors requests
* This is called by `request` when the portal/self response is intercepted
* and the `.authorizedCrossOriginNoCorsDomains` property is set.
* @param authorizedCrossOriginNoCorsDomains
*/
function registerNoCorsDomains(authorizedCrossOriginNoCorsDomains) {
// register the domains
authorizedCrossOriginNoCorsDomains.forEach((domain) => {
// ensure domain is lower case and ensure protocol is included
domain = domain.toLowerCase();
if (/^https?:\/\//.test(domain)) {
addNoCorsDomain(domain);
}
else {
// no protocol present, so add http and https
addNoCorsDomain("http://" + domain);
addNoCorsDomain("https://" + domain);
}
});
}
exports.registerNoCorsDomains = registerNoCorsDomains;
/**
* Ensure we don't get duplicate domains in the no-cors domains list
* @param domain
*/
function addNoCorsDomain(url) {
// Since the caller of this always ensures a protocol is present
// we can safely use the URL constructor to get the origin
// and add it to the no-cors domains list
const uri = new URL(url);
const domain = uri.origin;
if (requestConfig_js_1.requestConfig.noCorsDomains.indexOf(domain) === -1) {
requestConfig_js_1.requestConfig.noCorsDomains.push(domain);
}
}
/**
* Is the origin of the passed url in the no-cors domains list?
* @param url
* @returns
*/
function isNoCorsDomain(url) {
let result = false;
if (requestConfig_js_1.requestConfig.noCorsDomains.length) {
// is the current url in the no-cors domains?
const origin = new URL(url).origin.toLowerCase();
result = requestConfig_js_1.requestConfig.noCorsDomains.some((domain) => {
return origin.includes(domain);
});
}
return result;
}
exports.isNoCorsDomain = isNoCorsDomain;
/**
* Is the origin of the passed url in the no-cors domains list
* and do we need to send a no-cors request?
*
* @param url
* @returns
*/
function isNoCorsRequestRequired(url) {
let result = false;
// is the current origin in the no-cors domains?
if (isNoCorsDomain(url)) {
const origin = new URL(url).origin.toLowerCase();
// check if we have sent a no-cors request to this domain in the last hour
const lastRequest = requestConfig_js_1.requestConfig.crossOriginNoCorsDomains[origin] || 0;
if (Date.now() - 60 * 60000 > lastRequest) {
result = true;
}
}
return result;
}
exports.isNoCorsRequestRequired = isNoCorsRequestRequired;
//# sourceMappingURL=sendNoCorsRequest.js.map