[html] Is it valid to replace http:// with // in a <script src="http://...">?

I have the following element:

<script type="text/javascript" src="https://cdn.example.com/js_file.js"></script>

In this case the site is HTTPS, but the site may also be just HTTP. (The JS file is on another domain.) I'm wondering if it's valid to do the following for convenience sake:

<script type="text/javascript" src="//cdn.example.com/js_file.js"></script>

I'm wondering if it's valid to remove the http: or https:?

It seems to work everywhere I have tested, but are there any cases where it doesn't work?

This question is related to html http https uri protocol-relative

The answer is


1. Summary

Answer for 2019: you can still use protocol-relative URLs, but this technique an anti-pattern.

Also:

  1. You may have problems in developing.
  2. Some third-party tools may not support them.

Migrating from protocol-relative URLs to https:// it would be nice.


2. Relevance

This answer is relevant for January 2019. In the future, the data of this answer may be obsolete.


3. Anti-pattern

3.1. Argumentation

Paul Irish — front-end engineer and a developer advocate for the Google Chromewrite in 2014, December:

Now that SSL is encouraged for everyone and doesn’t have performance concerns, this technique is now an anti-pattern. If the asset you need is available on SSL, then always use the https:// asset.

Allowing the snippet to request over HTTP opens the door for attacks like the recent GitHub Man-on-the-side attack. It’s always safe to request HTTPS assets even if your site is on HTTP, however the reverse is not true.

3.2. Another links

3.3. Examples


4. Developing process

For example, I try to use clean-console.

  • Example file KiraCleanConsole__cdn_links_demo.html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>clean-console without protocol demonstration</title>
    <!-- Really dead link -->
    <script src="https://unpkg.com/bowser@latest/bowser.min.js"></script>
    <!-- Package exists; link without “https:” -->
    <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
    <!-- Package exists: link with “https:” -->
    <script src="https://cdn.jsdelivr.net/npm/gemini-scrollbar/index.js"></script>
</head>
<body>
    Kira Goddess!
</body>
</html>
  • output:
D:\SashaDebugging>clean-console -i KiraCleanConsole__cdn_links_demo.html
checking KiraCleanConsole__cdn_links_demo.html
phantomjs: opening page KiraCleanConsole__cdn_links_demo.html

phantomjs: Unable to load resource (#3URL:file://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js)


phantomjs:   phantomjs://code/runner.js:30 in onResourceError
Error code: 203. Description: Error opening //cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js: The network path was not found.

  phantomjs://code/runner.js:31 in onResourceError

phantomjs: Unable to load resource (#5URL:https://unpkg.com/[email protected]/bowser.min.js)


phantomjs:   phantomjs://code/runner.js:30 in onResourceError
Error code: 203. Description: Error downloading https://unpkg.com/[email protected]/bowser.min.js - server replied: Not Found

  phantomjs://code/runner.js:31 in onResourceError

phantomjs: Checking errors after sleeping for 1000ms
2 error(s) on KiraCleanConsole__cdn_links_demo.html

phantomjs process exited with code 2

Link //cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js is valid, but I getting an error.

Pay attention to file://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js and read Thilo and bg17aw answers about file://.

I didn't know about this behavior and couldn't understand why I have problems like this for pageres.


5. Third-party tools

I use Clickable URLs Sublime Text package. Use it, I can simply open links from my text editor in browser.

CSS links examples

Both links in example are valid. But first link I can successfully open in browser use Clickable URLs, second link — no. This may not be very convenient.


6. Conclusion

Yes:

  1. If you have problems as in Developing process item, you can set your development workflow.
  2. Else you have problems as in Third-party tools item, you can contribute tools.

But you don't need this additional problems. Read information by links in Anti-pattern item: protocol-relative URLs is obsolete.


Yes, this is documented in RFC 3986, section 5.2:

(edit: Oops, my RFC reference was outdated).


As your example is linking to an external domain, if you are using HTTPS then you should verify that the external domain is setup for SSL as well. Otherwise, your users may see SSL errors and/or 404 errors (e.g. older versions of Plesk store HTTP and HTTPS in separate folders). For CDNs, it shouldn't be an issue but for any other website it could be.

On a side note, tested while updated an old website and also works in the url= part of a META REFRESH.


Following the gnud's reference, the RFC 3986 section 5.2 says:

If the scheme component is defined, indicating that the reference starts with a scheme name, then the reference is interpreted as an absolute URI and we are done. Otherwise, the reference URI's scheme is inherited from the base URI's scheme component.

So // is correct :-)


It is indeed correct, as other answers have stated. You should note though, that some web crawlers will set off 404s for these by requesting them on your server as if a local URL. (They disregard the double slash and treat it as a single slash).

You may want to set up a rule on your webserver to catch these and redirect them.

For example, with Nginx, you'd add something like:

location ~* /(?<redirect_domain>((([a-z]|[0-9]|\-)+)\.)+([a-z])+)/(?<redirect_path>.*) {
  return 301 $scheme:/$redirect_domain/$redirect_path;
}

Do note though, that if you use periods in your URIs, you'll need to increase the specificity or it will end up redirecting those pages to nonexistent domains.

Also, this is a rather massive regex to be running for each query -- in my opinion, it's worth punishing non-compliant browsers with 404s over a (slight) performance hit on the majority of compliant browsers.


It is guaranteed to work in any mainstream browser (I'm not taking browsers with less than 0.05% market share into consideration). Heck, it works in Internet Explorer 3.0.

RFC 3986 defines a URI as composed of the following parts:

     foo://example.com:8042/over/there?name=ferret#nose
     \_/   \______________/\_________/ \_________/ \__/
      |           |            |            |        |
   scheme     authority       path        query   fragment

When defining relative URIs (Section 5.2), you can omit any of those sections, always starting from the left. In pseudo-code, it looks like this:

 result = ""

  if defined(scheme) then
     append scheme to result;
     append ":" to result;
  endif;

  if defined(authority) then
     append "//" to result;
     append authority to result;
  endif;

  append path to result;

  if defined(query) then
     append "?" to result;
     append query to result;
  endif;

  if defined(fragment) then
     append "#" to result;
     append fragment to result;
  endif;

  return result;

The URI you are describing is a scheme-less relative URI.


are there any cases where it doesn't work?

Just to throw this in the mix, if you are developing on a local server, it might not work. You need to specify a scheme, otherwise the browser may assume that src="//cdn.example.com/js_file.js" is src="file://cdn.example.com/js_file.js", which will break since you're not hosting this resource locally.

Microsoft Internet Explorer seem to be particularly sensitive to this, see this question: Not able to load jQuery in Internet Explorer on localhost (WAMP)

You would probably always try to find a solution that works on all your environments with the least amount of modifications needed.

The solution used by HTML5Boilerplate is to have a fallback when the resource is not loaded correctly, but that only works if you incorporate a check:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<!-- If jQuery is not defined, something went wrong and we'll load the local file -->
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script>

UPDATE: HTML5Boilerplate now uses <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js after deciding to deprecate protocol relative URLs, see [here][3].


The pattern I see on html5-boilerplate is:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script>

It runs smoothly on different schemes like http, https, file.


Many people call this a Protocol Relative URL.

It causes a double-download of CSS files in IE 7 & 8.


We are seeing 404 errors in our logs when using //somedomain.com as references to JS files.

The references that cause the 404s come out looking like this: ref:

<script src="//somedomain.com/somescript.js" />

404 request:

http://mydomain.com//somedomain.com/somescript.js

With these showing up regularly in our web server logs, it is safe to say that: All browsers and Bots DO NOT honor RFC 3986 section 4.2. The safest bet is to include the protocol whenever possible.


Here I duplicate the answer in Hidden features of HTML:

Using a protocol-independent absolute path:

<img src="//domain.com/img/logo.png"/>

If the browser is viewing an page in SSL through HTTPS, then it'll request that asset with the https protocol, otherwise it'll request it with HTTP.

This prevents that awful "This Page Contains Both Secure and Non-Secure Items" error message in IE, keeping all your asset requests within the same protocol.

Caveat: When used on a <link> or @import for a stylesheet, IE7 and IE8 download the file twice. All other uses, however, are just fine.


are there any cases where it doesn't work?

If the parent page was loaded from file://, then it probably does not work (it will try to get file://cdn.example.com/js_file.js, which of course you could provide locally as well).


It is perfectly valid to leave off the protocol. The URL spec has been very clear about this for years, and I've yet to find a browser that doesn't understand it. I don't know why this technique isn't better known; it's the perfect solution to the thorny problem of crossing HTTP/HTTPS boundaries. More here: Http-https transitions and relative URLs


Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to http

Access blocked by CORS policy: Response to preflight request doesn't pass access control check Axios Delete request with body and headers? Read response headers from API response - Angular 5 + TypeScript Android 8: Cleartext HTTP traffic not permitted Angular 4 HttpClient Query Parameters Load json from local file with http.get() in angular 2 Angular 2: How to access an HTTP response body? What is HTTP "Host" header? Golang read request body Angular 2 - Checking for server errors from subscribe

Examples related to https

What's the net::ERR_HTTP2_PROTOCOL_ERROR about? Requests (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.") Error in PyCharm requesting website Android 8: Cleartext HTTP traffic not permitted ssl.SSLError: tlsv1 alert protocol version Invalid self signed SSL cert - "Subject Alternative Name Missing" How do I make a https post in Node Js without any third party module? Page loaded over HTTPS but requested an insecure XMLHttpRequest endpoint How to force Laravel Project to use HTTPS for all routes? Could not create SSL/TLS secure channel, despite setting ServerCertificateValidationCallback Use .htaccess to redirect HTTP to HTTPs

Examples related to uri

Get Path from another app (WhatsApp) What is the difference between resource and endpoint? Convert a file path to Uri in Android How do I delete files programmatically on Android? java.net.MalformedURLException: no protocol on URL based on a string modified with URLEncoder How to get id from URL in codeigniter? Get real path from URI, Android KitKat new storage access framework Use URI builder in Android or create URL with variables Converting of Uri to String How are parameters sent in an HTTP POST request?

Examples related to protocol-relative

Is it valid to replace http:// with // in a <script src="http://...">?