Firefox experiences Network Protocol Violation on Discourse based Websites

This is 100000% percent a Firefox issue / insane service worker standards issue. Discourse are consuming a web platform feature, unfortunately only Chrome appears to be implementing it well. Safari is “uneven”, Firefox has these issues.

So yeah, not our fault, but this feature of request interception is only there for Android pwa, it has been around in multiple reincarnations for about a year causing a constant trickle of support

5 Likes

Not quite, I didn’t put the blame on anyone, rather said that this was behaviour that could be fixed within Discourse. As @sam said this is a more of a quirk of web standards than anything else:

As the standard for navigator.onLine notes:

This attribute is inherently unreliable. A computer can be connected to a network without having Internet access.

If you want to read the full, chequered, history of the feature in Firefox, make yourself a :tea: and pull up a chair:

(Please don’t comment in that bug, it’s far too long and old, it’s closed, and will probably be ignored. Instead open a new bug.)

And as I mentioned before, Firefox could let Service Workers fail a little more gracefuly:

But if you want a fix now, you could take the nuclear option and disable Service Workers entirely in Firefox:

  1. Head to about:config.
  2. Search for dom.serviceWorkers.enabled
  3. Toggle it to false

Toggle it to true if you want to enable Service Workers again.

5 Likes

That does indeed fix it, I can’t replicate it in known situations where it happens reliably now that, that is disabled. Not something I can ask everyone who visits to do though (especially when they never get into the site to see such instructions anyway). :slight_smile:

3 Likes

So uhm it has been a few weeks, and I still get this Issue on here. Considering there has been conflicting information here whether this gets fixed or not, I would like to ask if it is going to be, since you kinda gave a very rough eta on this.

Also for some reason it doesn’t happen on my own Discourse Forums anymore (at least to me), but it still happens here (even after clearing caches and stuff), so I presume something happened in the meantime and you guys just didnt update meta recently?

Meta is updated on every commit to Discourse.

By the way, I moved to full time Firefox in the last few weeks, and since I’m still setting my Multi-Account Containers I’m logging a lot in many different Discourse instances and never faced this error.

1 Like

I got this one time in about a month of full time use

I’d be interested to know if this fix does stop your Firefox problem on meta? Just to clarify that your problem on meta is not caused by something else.

1 Like

If you fixed it then it did not work, I still get it when I middleclick the Bookmark towards this Thread, even after full refresh.

I think that you misunderstood me. I’m a Firefox user who doesn’t have the problem and I’m not part of the Discourse team.

If you disable the service workers as @OvermindDL1 did, then the problem should go away. If the problem remains then that suggests that you are having a different issue which might explain why you are still having this problem when others are not.

1 Like

Oh, that one, just tried it, still Errors when I open the Page in a new Tab, so I guess either the Config itself is broken or the origin of the problem is something else for some reason.

(And I am used to have quotes above posts where I am usually around, so I misunderstood that one, sorry :wink: )

1 Like

FINALLY I GOT A REPRO ON THIS!

While trying to access the page at https://forum-enqueteurs.fr/t/liste-des-societes-de-clients-mysteres-enqueteurs-auditeurs/19 I got the famous:

Then I went to the WebConsole and found the actual error:

Failed to load ‘https://forum-enqueteurs.fr/t/liste-des-societes-de-clients-mysteres-enqueteurs-auditeurs/19’. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with ‘Error: TypeError: NetworkError when attempting to fetch resource.’.

Hmmm, Network error, let’s see what cURL says:

➜  discourse git:(master) curl -vv https://forum-enqueteurs.fr/t/liste-des-societes-de-clients-mysteres-enqueteurs-auditeurs/19
*   Trying 51.38.233.14...
* TCP_NODELAY set
* Connected to forum-enqueteurs.fr (51.38.233.14) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=www.forum-enqueteurs.fr
*  start date: Oct 19 22:02:50 2018 GMT
*  expire date: Jan 17 22:02:50 2019 GMT
*  subjectAltName does not match forum-enqueteurs.fr
* SSL: no alternative certificate subject name matches target host name 'forum-enqueteurs.fr'
* stopped the pause stream!
* Closing connection 0
* TLSv1.2 (OUT), TLS alert, Client hello (1):
curl: (51) SSL: no alternative certificate subject name matches target host name 'forum-enqueteurs.fr'

So, at least this instance, looks like another error that was swallowed.

Adding an --insecure to cURL shows that the response is actually a 301 Permanent Redirect to the www subdomain, but done without a valid certificate and under a HSTS protected domain.

6 Likes

Weird, because when I try to open this in Firefox I just get a certificate error, like is to be expected.
To be honest, I do not have the feeling that this is a repro of the actual issue. This is just a certificate issue.

Also, I have seen the “Network Protocol Violation” on sites that did not have HSTS, nor certificate problems.

1 Like

Was that the first time you went to that site? Makes sense to see the original error, since the service worker will only be installed during the first visit.

1 Like

Hrrm, while setting up Discourse, early on, there had been a lot of subdomain changes during testing (until it finally got settled), maybe it has to do something with the Service Worker somehow keeping the old Subdomain, when trying to access the new Subdomain in offline Mode.

But then again it wouldn’t Error offline, since offline is offline and there is no internet. And I do get the Error when there is no Internet whatsoever.

That makes sense. But that still does not make this specific repro representative for the issue people are reporting. It happens intermittently and in situations where there are no certificate issues.

1 Like

Yeah, that’s true. But since Firefox is throwing this error around (Corrupted Content) for any network level error that happens in a fetch inside a service worker my guess is that it’s a red herring for connectivity problems, aka the page wouldn’t load anyway but with a different error.

And until someone can give proper reproduction steps like I did above, it’s hard to come up with new hypothesis.

6 Likes

I think that is the most accurate explanation so far :slight_smile:

4 Likes

I have also consistently got this ‘Corrupted Content’ error on up to date FF on up to date Windows 10 when visiting http://clojureverse.org/ over the past year (since joining it in Dec '17).

Refresh (Ctrl-R) always loads page correctly but boy is it frustrating :-/

2 Likes

Screenshot of console when after req fails - breakpoint set before content error screen loads:

err msg:

Failed to load ‘https://clojureverse.org/t/java-10-announcement-implications-for-clojure/1583’. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with ‘Error: TypeError: NetworkError when attempting to fetch resource.’.

i would step further in to this but debugging in FF is useless compared to Chrome(my normal dev browser)
clicking through that service-worker in err msg link just brings me to a v. basic ‘view source’ screen[0]:

looking at that line number in something better and at column 1396

which is the ‘new’ in if (navigator.onLine) throw new Error(e); from:

 self.addEventListener("fetch", function(e) {
    /\?.*token/i.test(e.request.url) || ("navigate" === e.request.mode || "GET" === e.request.method && e.request.headers.get("accept").includes("text/html")) && e.respondWith(fetch(e.request).catch(function(e) {
        if (navigator.onLine) throw new Error(e);
        return caches.match(OFFLINE_URL)
    }))

[0]

 "use strict";function createCacheBustedRequest(e){var t=new Headers({"Discourse-Track-View":"0"}),n=new Request(e,{cache:"reload",headers:t});if("cache"in n)return n;var i=new URL(e,self.location.href);return i.search+=(i.search?"&":"")+"cachebust="+Date.now(),new Request(i,{headers:t})}function isIdle(){return lastAction+idleThresholdTime<Date.now()}function showNotification(e,t,n,i,a,s,o){var c={body:t,icon:n,badge:i,data:{url:o,baseUrl:s},tag:a};return self.registration.showNotification(e,c)}const CACHE_VERSION=1,CURRENT_CACHES={offline:"offline-v1"},OFFLINE_URL="offline.html";self.addEventListener("install",function(e){e.waitUntil(fetch(createCacheBustedRequest(OFFLINE_URL)).then(function(e){return caches.open(CURRENT_CACHES.offline).then(function(t){return t.put(OFFLINE_URL,e)})}).then(function(e){self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=Object.keys(CURRENT_CACHES).map(function(e){return CURRENT_CACHES[e]});e.waitUntil(caches.keys().then(function(e){return Promise.all(e.map(function(e){if(-1===t.indexOf(e))return caches.delete(e)}))}).then(function(){self.clients.claim()}))}),self.addEventListener("fetch",function(e){/\?.*token/i.test(e.request.url)||("navigate"===e.request.mode||"GET"===e.request.method&&e.request.headers.get("accept").includes("text/html"))&&e.respondWith(fetch(e.request).catch(function(e){if(navigator.onLine)throw new Error(e);return caches.match(OFFLINE_URL)}))});const idleThresholdTime=1e4;var lastAction=-1;self.addEventListener("push",function(e){var t=e.data.json();if(!isIdle()&&t.hide_when_active)return!1;e.waitUntil(self.registration.getNotifications({tag:t.tag}).then(function(e){return e&&e.length>0&&e.forEach(function(e){e.close()}),showNotification(t.title,t.body,t.icon,t.badge,t.tag,t.base_url,t.url)}))}),self.addEventListener("notificationclick",function(e){e.notification.close();var t=e.notification.data.url,n=e.notification.data.baseUrl;e.waitUntil(clients.matchAll({type:"window"}).then(function(e){if(!e.some(function(e){return e.url===n+t&&"focus"in e?(e.focus(),!0):"postMessage"in e&&"focus"in e&&(e.focus(),e.postMessage({url:t}),!0)})&&clients.openWindow)return clients.openWindow(n+t)}))}),self.addEventListener("message",function(e){"lastAction"in e.data&&(lastAction=e.data.lastAction)}); //# sourceMappingURL=/assets/service-worker-b3132ce44c958878a3dc19776072ad3861a661ca983e3c8f0269c27a439d47d2.js.map
6 Likes

some network traffic.

showing just headers for the initial CONNECT:
REQ 1

CONNECT clojureverse.org:443 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0
Connection: keep-alive
Connection: keep-alive
Host: clojureverse.org:443 

RES 1

HTTP/1.1 200 Connection Established

REQ 2:

GET https://clojureverse.org/service-worker-b3132ce44c958878a3dc19776072ad3861a661ca983e3c8f0269c27a439d47d2.js HTTP/1.1
Host: clojureverse.org
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en,en-US;q=0.5
Accept-Encoding: gzip, deflate, br
Service-Worker: script
Connection: keep-alive
Cookie: _t=c3b58bc93fb8e48129ae3926c6676c6d; __cfduid=dd2ad00ecc6e6daf1d81d20dc1e27671d1536612308
Pragma: no-cache
Cache-Control: no-cache

RES 2:

 HTTP/1.1 200 OK
Date: Fri, 26 Oct 2018 16:11:07 GMT
Content-Type: application/javascript; charset=utf-8
Connection: keep-alive
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Referrer-Policy: strict-origin-when-cross-origin
X-Discourse-Route: static/service_worker_asset
Last-Modified: Sat, 23 Jun 2018 10:59:28 GMT
Cache-Control: public, max-age=31556952
X-Request-Id: 834906b4-6490-402d-8540-e7a845411260
CF-Cache-Status: HIT
Expires: Sat, 26 Oct 2019 22:00:19 GMT
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 46fe326bac0da701-DUB
Content-Length: 2418

 "use strict";function createCacheBustedRequest(e){var t=new Headers({"Discourse-Track-View":"0"}),n=new Request(e,{cache:"reload",headers:t});if("cache"in n)return n;var i=new URL(e,self.location.href);return i.search+=(i.search?"&":"")+"cachebust="+Date.now(),new Request(i,{headers:t})}function isIdle(){return lastAction+idleThresholdTime<Date.now()}function showNotification(e,t,n,i,a,s,o){var c={body:t,icon:n,badge:i,data:{url:o,baseUrl:s},tag:a};return self.registration.showNotification(e,c)}const CACHE_VERSION=1,CURRENT_CACHES={offline:"offline-v1"},OFFLINE_URL="offline.html";self.addEventListener("install",function(e){e.waitUntil(fetch(createCacheBustedRequest(OFFLINE_URL)).then(function(e){return caches.open(CURRENT_CACHES.offline).then(function(t){return t.put(OFFLINE_URL,e)})}).then(function(e){self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=Object.keys(CURRENT_CACHES).map(function(e){return CURRENT_CACHES[e]});e.waitUntil(caches.keys().then(function(e){return Promise.all(e.map(function(e){if(-1===t.indexOf(e))return caches.delete(e)}))}).then(function(){self.clients.claim()}))}),self.addEventListener("fetch",function(e){/\?.*token/i.test(e.request.url)||("navigate"===e.request.mode||"GET"===e.request.method&&e.request.headers.get("accept").includes("text/html"))&&e.respondWith(fetch(e.request).catch(function(e){if(navigator.onLine)throw new Error(e);return caches.match(OFFLINE_URL)}))});const idleThresholdTime=1e4;var lastAction=-1;self.addEventListener("push",function(e){var t=e.data.json();if(!isIdle()&&t.hide_when_active)return!1;e.waitUntil(self.registration.getNotifications({tag:t.tag}).then(function(e){return e&&e.length>0&&e.forEach(function(e){e.close()}),showNotification(t.title,t.body,t.icon,t.badge,t.tag,t.base_url,t.url)}))}),self.addEventListener("notificationclick",function(e){e.notification.close();var t=e.notification.data.url,n=e.notification.data.baseUrl;e.waitUntil(clients.matchAll({type:"window"}).then(function(e){if(!e.some(function(e){return e.url===n+t&&"focus"in e?(e.focus(),!0):"postMessage"in e&&"focus"in e&&(e.focus(),e.postMessage({url:t}),!0)})&&clients.openWindow)return clients.openWindow(n+t)}))}),self.addEventListener("message",function(e){"lastAction"in e.data&&(lastAction=e.data.lastAction)});
//# sourceMappingURL=/assets/service-worker-b3132ce44c958878a3dc19776072ad3861a661ca983e3c8f0269c27a439d47d2.js.map
1 Like