swagger-ui: Swagger ui 'Try it out!' calls http on https page and the request is blocked

My swagger.json is the following (replacing ‘…’ and ‘IP’ with some data):

{
    "swagger": "2.0",
    "info": {
        "version": "v1",
        "title": "Documentation for API",
        "description": "..."
    },
    "host": "IP:3030",
    "schemes": ["http", "https"],
    "paths": {
        "...": { ... }
    },
    "definitions": {
        "...": { ... }
    }
}

And I’m calling the swagger-ui in this function (docs.js):

$(function () {
    var version = window.location.href.match(/v\d+(\.\d+)*/); //any v1, v1.2, v1.2.3 ...
    version = version && version[0] ? version[0] : 'v1';
    var url = window.location.origin + '/docs/' + version;

    window.swaggerUi = new SwaggerUi({
        url: url,
        dom_id: "swagger-ui-container",
        validatorUrl: null,
        supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
        onComplete: function (swaggerApi, swaggerUi) {
            console.log("Loaded SwaggerUI");

            $('pre code').each(function (i, e) {
                hljs.highlightBlock(e)
            });

            $('#api_info').addClass('container');
            $('input[name=grant_type]').val('password');
        },
        onFailure: function (data) {
           console.log("Unable to Load SwaggerUI");
        },
        docExpansion: "none",
        apisSorter: "alpha",
        //operationsSorter: "alpha"
    });

    window.swaggerUi.load();
});

And the index.html is this:

<!DOCTYPE html>
<html>
<head>
    <meta content="IE=edge, chrome=1" http-equiv="X-UA-Compatible" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <link rel="shortcut icon" href="/favicon.ico" />
    <title>API Docs</title>
    <link href="/docs/css/typography.css" media="all" rel="stylesheet" type="text/css" />
    <link href="/docs/css/reset.css" media="all" rel="stylesheet" type="text/css" />
    <link href="/docs/css/screen.css" media="all" rel="stylesheet" type="text/css" />
    <link href="/app/css/bootswatch/bootstrap.min.css" media="all" rel="stylesheet" type="text/css" />
    <link href="/app/css/site.css" media="all" rel="stylesheet" type="text/css" />

    <script src="/docs/lib/jquery-1.8.0.min.js" type="text/javascript"></script>
    <script src="/docs/lib/jquery.slideto.min.js" type="text/javascript"></script>
    <script src="/docs/lib/jquery.wiggle.min.js" type="text/javascript"></script>
    <script src="/docs/lib/jquery.ba-bbq.min.js" type="text/javascript"></script>
    <script src="/docs/lib/handlebars-2.0.0.js" type="text/javascript"></script>
    <script src="/docs/lib/underscore-min.js" type="text/javascript"></script>
    <script src="/docs/lib/backbone-min.js" type="text/javascript"></script>
    <script src="/docs/swagger-ui.js" type="text/javascript"></script>
    <script src="/docs/lib/highlight.7.3.pack.js" type="text/javascript"></script>
    <script src="/docs/lib/marked.js" type="text/javascript"></script>

    <!-- enabling this will enable oauth2 implicit scope support -->
    <!--<script src="lib/swagger-oauth.js" type="text/javascript"></script>-->
    <script src="/docs/docs.js" type="text/javascript"></script>
</head>
<body class="swagger-section">
    <div class="navbar navbar-default navbar-fixed-top" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button class="btn btn-success navbar-toggle">
                    <span class="glyphicon glyphicon-chevron-down"></span>
                </button>
                <a class="navbar-brand" href="/">
                    <img src="/app/images/logogif" alt="Logo" />
                </a>
            </div>
        </div>
    </div>

    <div style="margin-top:65px">
        <div id="message-bar" class="swagger-ui-wrap">&nbsp;</div>
        <div id="swagger-ui-container" class="swagger-ui-wrap"></div>
    </div>
</body>
</html>

When I ‘Try it out!’ my methods, I’m getting the following error on Google Chrome:

Mixed Content: The page at ‘https://IP:3030/docs/#!/Auth/AuthHb_Login’ was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint ‘http://IP:3030/api/auth’. This request has been blocked; the content must be served over HTTPS.

Should my swagger.json “schemes” be only [“https”] ? I’m asking this, because I have dev, uat and prod environments and we don’t use https in dev (just in uat and production).

By the way, I’m using Swashbuckle (.NET) and swagger-ui.js version 2.1.0 (using the pre-built files in the dist folder). Related issue #1006.

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 10
  • Comments: 22 (7 by maintainers)

Commits related to this issue

Most upvoted comments

@webron, digging the code I discovered the problem’s origin:

It’s actually on swagger-client.js line 259.

SwaggerClient.prototype.buildFromSpec = function (response) {
...
if (typeof this.url === 'string') {
    location = this.parseUri(this.url);
    if (typeof this.schemes === 'undefined' || this.schemes.length === 0) {
      this.scheme = location.scheme || 'http';
    } else {
      this.scheme = this.schemes[0];  //line 259
    }

    if (typeof this.host === 'undefined' || this.host === '') {
      this.host = location.host;

      if (location.port) {
        this.host = this.host + ':' + location.port;
      }
    }
  }
  else {
    if (typeof this.schemes === 'undefined' || this.schemes.length === 0) {
      this.scheme = 'http';
    }
    else {
      this.scheme = this.schemes[0];
    }
  }

If the spec doesn’t have schemes, it’s getting location.scheme or default scheme, http. this.scheme = location.scheme || 'http';, but if it has schemes, it gets the first scheme. this.scheme = this.schemes[0];

As I’m intentionally sending "schemes": ["http", "https"] (as I can have both depending on environment), it always gets “http”, even on https page and the request is blocked by the browser.

I believe it should be:

if (typeof this.schemes === 'undefined' || this.schemes.length === 0) {
    this.scheme = location.scheme || 'http';
} else {
    this.scheme = location.scheme || this.schemes[0];
}

Or even better, test if the page is https, because calling http on https page won’t work anyway.

What do you think?

I can fork the swagger-js repo and make a pull request changing it if you agree. And I can open the same issue there as well.

As a workaround, not setting schemes on swagger.json also works (what I’m gonna do temporarily).

Setting order to http and then https worked for me using 2.1.4 but after updating to 2.2.3 I am having the same issues again; the first one speicified is always the one being used.

Please specify https as the first supported scheme in your spec and it’ll pick that up.

This work.

findReact() method

var findReact = function(dom) {
    for (var key in dom) {
        if (key.startsWith("__reactInternalInstance$")) {
            var compInternals = dom[key]._currentElement;
            var compWrapper = compInternals._owner;
            var comp = compWrapper._instance;
            return comp;
        }
    }
    return null;
};


Set https scheme:

var ui = SwaggerUIBundle({
   // ....
  onComplete: function() {
     var schemeSelect = document.querySelector('.scheme-container select');
     FindReact(schemeSelect).setScheme('https');
   }
});