From fb7f12551f234684abe9c02d36713b597c263beb Mon Sep 17 00:00:00 2001 From: Scott O'Hara Date: Tue, 13 Mar 2018 10:57:51 +1100 Subject: [PATCH] improve: show possible reasons when url fetch fails (#4295) * improve: show possible reasons when url fetch fails * Only check for fail reasons if no HTTP status code * Check for mixed content errors first * Harmonise error messages * Set error source to 'fetch' * improve: hide loading validator image (#4287) * hide missing validator image * Render nothing if validator badge has not loaded/received errors * Revert style changes * Allow images with data scheme (#4305) * Add UnitTest for image allows image elements with https scheme * Test images with data scheme * Add allowedSchemesByTag * Fix error Strings must use doublequote quotes * Add empty div (#4236) if there are properties show an empty div * v3.12.1 (#4311) * v3.12.1 * Rebuild dist for v3.12.1 * Use window wrapper instead of direct reference * Add trailing period to error messages * improve readability --- src/core/plugins/download-url.js | 39 +++++++++++++++++++++++++++++++- src/standalone/layout.jsx | 5 ++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/core/plugins/download-url.js b/src/core/plugins/download-url.js index 6439eec8..495cfd2d 100644 --- a/src/core/plugins/download-url.js +++ b/src/core/plugins/download-url.js @@ -2,6 +2,7 @@ import { createSelector } from "reselect" import { Map } from "immutable" +import win from "../window" export default function downloadUrlPlugin (toolbox) { let { fn } = toolbox @@ -12,6 +13,7 @@ export default function downloadUrlPlugin (toolbox) { const config = getConfigs() url = url || specSelectors.url() specActions.updateLoadingStatus("loading") + errActions.clear({source: "fetch"}) fetch({ url, loadSpec: true, @@ -26,7 +28,10 @@ export default function downloadUrlPlugin (toolbox) { function next(res) { if(res instanceof Error || res.status >= 400) { specActions.updateLoadingStatus("failed") - return errActions.newThrownErr( new Error((res.message || res.statusText) + " " + url) ) + errActions.newThrownErr(Object.assign( new Error((res.message || res.statusText) + " " + url), {source: "fetch"})) + // Check if the failure was possibly due to CORS or mixed content + if (!res.status && res instanceof Error) checkPossibleFailReasons() + return } specActions.updateLoadingStatus("success") specActions.updateSpec(res.text) @@ -35,6 +40,38 @@ export default function downloadUrlPlugin (toolbox) { } } + function checkPossibleFailReasons() { + try { + let specUrl + + if("URL" in win ) { + specUrl = new URL(url) + } else { + // legacy browser, use to parse the URL + specUrl = document.createElement("a") + specUrl.href = url + } + + if(specUrl.protocol !== "https:" && win.location.protocol === "https:") { + const error = Object.assign( + new Error(`Possible mixed-content issue? The page was loaded over https:// but a ${specUrl.protocol}// URL was specified. Check that you are not attempting to load mixed content.`), + {source: "fetch"} + ) + errActions.newThrownErr(error) + return + } + if(specUrl.origin !== win.location.origin) { + const error = Object.assign( + new Error(`Possible cross-origin (CORS) issue? The URL origin (${specUrl.origin}) does not match the page (${win.location.origin}). Check the server returns the correct 'Access-Control-Allow-*' headers.`), + {source: "fetch"} + ) + errActions.newThrownErr(error) + } + } catch (e) { + return + } + } + }, updateLoadingStatus: (status) => { diff --git a/src/standalone/layout.jsx b/src/standalone/layout.jsx index a3a7d98c..c4f85f55 100644 --- a/src/standalone/layout.jsx +++ b/src/standalone/layout.jsx @@ -21,6 +21,7 @@ export default class StandaloneLayout extends React.Component { let Container = getComponent("Container") let Row = getComponent("Row") let Col = getComponent("Col") + let Errors = getComponent("errors", true) const Topbar = getComponent("Topbar", true) const BaseLayout = getComponent("BaseLayout", true) @@ -45,8 +46,8 @@ export default class StandaloneLayout extends React.Component {

Failed to load API definition.

-

{lastErrMsg}

-
+ +
} { loadingStatus === "failedConfig" &&