/* global PARAMS, XMLHttpRequest */ const STORAGE_URL = PARAMS.OS_STORAGE_URL || 'http://localhost:8080/v1/AUTH_test' function makeUrl (path) { if (path.startsWith('http://') || path.startsWith('https://')) { return new URL(path) } if (!path.startsWith('/')) { return new URL(STORAGE_URL + '/' + path) } return new URL(STORAGE_URL.substr(0, STORAGE_URL.indexOf('/', 3 + STORAGE_URL.indexOf('://'))) + path) } export function MakeRequest (method, path, headers, body, params) { var url = makeUrl(path) headers = headers || {} params = params || {} if (!( url.searchParams.has('Signature') || url.searchParams.has('X-Amz-Signature') || 'Authorization' in headers )) { // give each Swift request a unique query string to avoid ever fetching from cache params['cors-test-time'] = Date.now().toString() params['cors-test-random'] = Math.random().toString() } for (var key in params) { url.searchParams.append(key, params[key]) } return new Promise((resolve, reject) => { const req = new XMLHttpRequest() req.addEventListener('readystatechange', function () { if (this.readyState === 4) { resolve(this) } }) req.open(method, url.toString()) if (headers) { for (const name of Object.keys(headers)) { req.setRequestHeader(name, headers[name]) } } req.send(body) }) } export function HasStatus (expectedStatus, expectedMessage) { return function (resp) { if (resp.status !== expectedStatus) { throw new Error('Expected status ' + expectedStatus + ', got ' + resp.status) } if (resp.statusText !== expectedMessage) { throw new Error('Expected status text ' + expectedMessage + ', got ' + resp.statusText) } return resp } } export function HasHeaders (headers) { if (headers instanceof Array) { return function (resp) { const missing = headers.filter((h) => !resp.getResponseHeader(h)) if (missing.length) { throw new Error('Missing expected headers ' + JSON.stringify(missing) + ' in response: ' + resp.getAllResponseHeaders()) } return resp } } else { return function (resp) { const names = Object.keys(headers) const missing = names.filter((h) => !resp.getResponseHeader(h)) if (missing.length) { throw new Error('Missing expected headers ' + JSON.stringify(missing) + ' in response: ' + resp.getAllResponseHeaders()) } for (const name of names) { const value = resp.getResponseHeader(name) if (name === 'Etag') { // special case for Etag which may or may not be quoted if ((value !== headers[name]) && (value !== "\"" + headers[name] + "\"")) { throw new Error('Expected header ' + name + ' to have value ' + headers[name] + ', got ' + value) } } else if (value !== headers[name]) { throw new Error('Expected header ' + name + ' to have value ' + headers[name] + ', got ' + value) } } return resp } } } export function HasCommonResponseHeaders (resp) { // These appear in most *all* responses, but have unpredictable values HasHeaders([ 'Last-Modified', 'X-Openstack-Request-Id', 'X-Timestamp', 'X-Trans-Id', 'Content-Type' ])(resp) // Save that trans-id and request-id are the same thing if (resp.getResponseHeader('X-Trans-Id') !== resp.getResponseHeader('X-Openstack-Request-Id')) { throw new Error('Expected X-Trans-Id and X-Openstack-Request-Id to match; got ' + resp.getAllResponseHeaders()) } // These appear in most responses, but *aren't* (currently) exposed via CORS DoesNotHaveHeaders([ 'Accept-Ranges', 'Access-Control-Allow-Origin', 'Access-Control-Expose-Headers', 'Date', // Hmmm.... 'Content-Range', 'X-Account-Bytes-Used', 'X-Account-Container-Count', 'X-Account-Object-Count', 'X-Container-Bytes-Used', 'X-Container-Object-Count' ])(resp) return resp } export function DoesNotHaveHeaders (headers) { return function (resp) { const found = headers.filter((h) => resp.getResponseHeader(h)) if (found.length) { throw new Error('Found unexpected headers ' + found + ' in response: ' + resp.getAllResponseHeaders()) } return resp } } export function HasNoBody (resp) { if (resp.responseText !== '') { throw new Error('Expected no response body; got ' + resp.responseText) } return resp } export function BodyHasLength (expectedLength) { return (resp) => { if (resp.responseText.length !== expectedLength) { throw new Error('Expected body to have length ' + expectedLength + ', got ' + resp.responseText.length) } return resp } } export function CorsBlocked (resp) { // Yeah, there's *nothing* useful here -- gotta look at the browser's console if you want to see what happened HasStatus(0, '')(resp) const allHeaders = resp.getAllResponseHeaders() if (allHeaders !== '') { throw new Error('Expected no headers; got ' + allHeaders) } HasNoBody(resp) return resp } function _denial (status, text) { function Denial (resp) { HasStatus(status, text)(resp) const prefix = '