Instruct Cloudflare not to serve HTTP/3?

Hi there!

I work on a developer tool called PWABuilder, which helps developers build Progressive Web Apps (PWAs).

Cloudflare’s HTTP/3 support has been giving me many headaches lately.

Specifically, I use various backend services to fetch website content (manifests, service workers, images, and more). But most HTTP APIs – including those in Node, .NET, and Java – don’t currently support HTTP/3, as it’s still an experimental protocol.

What ends up happening is developers open issues asking why their sites aren’t working with my developer tools. I investigate, only to find that their sites are being served via Cloudflare’s experimental HTTP/3 support, often unknowingly.

Is there a way during my HTTP fetch calls to tell Cloudflare not to serve HTTP/3 requests? Request headers perhaps or some other way? I assume that Cloudflare can gracefully handle cases where HTTP/3 isn’t supported and fallback to HTTP/2 or 1.1. But I don’t see a way to advertise that to Cloudflare while making my programmatic HTTP fetch calls.

1 Like

Hi @judahgabriel,

Thanks for writing to the community forums, PWAs are cool!

I’m an engineer on the Cloudflare team responsible for QUIC and HTTP/3. As you might have seen on the blog recently, QUIC version 1 was published as RFC 9000 and it is now enabled fully on our edge. The HTTP/3 drafts are very close to being published as RFCs too, and the version that User Agents and the Cloudflare edge talk is as close as can be to the RFC version. For these reasons, HTTP/3 support is not classed as experimental.

I’m sorry that you and your are developers hitting issues. But given the status of HTTP/3, we’d really like to understand more about the problems that you seem to be encountering.

Can you explain a bit more about how PWABuilder works?

If you’re using the Fetch API, there is no way to control the connection-oriented aspects like HTTP version (this is by design, due to web security models).

I appreciate that having issues raised on your repo isn’t great, and requiring your users to turn off HTTP/3 for their Cloudflare zones isn’t so good either. It would be awesome if you could help us debug this a bit further to understand what is happening here to cause people to see 5xx errors.

Feel free to respond on this issue, or DM me.

6 Likes

Hey Lucas. Thanks for the reply.

I didn’t know HTTP/3 was standardized the other week. Thanks for the heads up. Amazing how fast the web evolves! I love it.

What I’m doing: using standard HTTP APIs (from Node, .NET, Java, etc.) to fetch resources from a developer’s PWA. A developer puts in “https://webboard.app” into PWABuilder, and PWABuilder web service analyzes their site, find their web manifest (e.g. manifest.json) and app icons listed in their web manifest.

The problem is that HTTP APIs in all the mainstream programming frameworks – Node, .NET, Java, Python, etc. – are unable to work with HTTP/3. Ditto for the myriads of tools built on top of these APIs, including PWABuilder. I love that Cloudflare is on the cutting edge with HTTP/3, but Clouldflare should provide a graceful fallback for HTTP clients that don’t support HTTP/3, no?

That’s what I’m asking for. Allow me to say in my HTTP request, “Hey, I only support HTTP/1.1” and Cloudflare should honor that.

Does that make sense?

Thanks for the added colour @judahgabriel .

So by default, when someone enables HTTP/3 on a Cloudflare zone, we listen on TCP for HTTP/1.1 and HTTP/2, and on UDP for HTTP/3. The client is the one in the driving seat to decide which port it opens and tries to speak to us on. To put it another way, the fallback is already there.

So the thing that confuses me here is that I would expect a framework to by default handle all of this for you without errors. Although the protocols are basically standard, it will take some time for support to filter down to stable frameworks. A framework that has no notion of HTTP/3 would just continue on with try HTTP/1.1 or HTTP/2. For a framework to try HTTP/3 without being configured to is a bit surprising (but possible maybe?). However, for it to fail with an application-level error like an HTTP status code or a malformed payload is really strange and should not happen - and that’s why I’m keen to find out if there is something untoward.

An alternative possibility is that your client code is struggling to speak to Cloudflare for some other reason unrelated to HTTP/3. For instance, maybe it’s hitting ratelimiting or DDoS prevention measures etc.

To really make progress on troubleshooting this, it would help to share with us the exact client details and the request/responses that it got. If this were a browser, I’d suggest sharing a HAR file for us to look at. But in this case framework client logs would probably suffice.

3 Likes

Hey Lucas,

Super cool to hear there’s a fallback in place.

Here’s a simple repro: Glitch :・゚✧

It just uses node-fetch to fetch a site served via Cloudflare.

node-fetch doesn’t support HTTP/3 or HTTP/2. So, I would expect Cloudflare to fallback and serve me HTTP/1.1.

Instead, I get a 503 error.

If the end user’s site turns off Cloudflare, the fetch call succeeds.

I remixed your reproduction to also show the body that’s being returned: Glitch :・゚✧

Looking at the body that’s being returned, it seems like you’re receiving Cloudflare’s JS challenge page, which would explain why you were seeing the expected content again after the end user turned off Cloudflare.


The website can make these challenge pages less frequent and/or disable them entirely by modifying their Cloudflare settings such as security level. Once that’s done, you should no longer see the challenge page when fetching the page.

From what I can tell, this issue does not seem to be related to HTTP/3, but rather that you’re just running into challenge pages because of the website’s security settings.

1 Like

Thanks @judahgabriel.

I think @arunesh90 answer is pretty accurate.

If node-fetch only supports HTTP/1.1 then it should just try that version and succeed. When you see a status code, it means that the HTTP handshake succeeded and that there was an application error.

I took the example glitch, and simplified it further by making a local node project with the following index.js contents of index.js, I get a 200 response back and all the payload that we would expect.

const fetch = require('node-fetch');

async function doIt() {
    const response = await fetch('https://sky.shiiyu.moe/');

    console.log(response.headers);
}

doIt();

then

$ node index.js

Headers {
  [Symbol(map)]: [Object: null prototype] {
    date: [ 'Mon, 28 Jun 2021 23:47:55 GMT' ],
    'content-type': [ 'text/html; charset=utf-8' ],
    'transfer-encoding': [ 'chunked' ],
    connection: [ 'close' ],
    vary: [ 'Accept-Encoding' ],
    'x-powered-by': [ 'Express' ],
    'x-cluster-id': [ 'w3' ],
    'x-process-time': [ '6' ],
    'cf-cache-status': [ 'DYNAMIC' ],
    'cf-request-id': [ '0af69ecedb00005428a4b21000000001' ],
    'expect-ct': [
      'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"'
    ],
    'report-to': [
      '{"endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v2?s=pMNsOtQhByFRsM%2FuVFesktyqqgRgaNKk%2ByVRegJSSny8fbKz8QvnA7RGvODXc7U%2BOqnuxaDYbq1XXNnlVqWmGW3Rlu4YN6mWOdRu6%2FjEiIcHzswEoiEynrqmiNo%3D"}],"group":"cf-nel","max_age":604800}'
    ],
    nel: [ '{"report_to":"cf-nel","max_age":604800}' ],
    server: [ 'cloudflare' ],
    'cf-ray': [ '666acd915a515428-LHR' ],
    'content-encoding': [ 'gzip' ],
    'alt-svc': [
      'h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400, h3=":443"; ma=86400'
    ]
  }
}

Based on this trace it’s likely that the Cloudflare mitigations like bot detection are kicking in due to the circumstance around how PWABuilder decides to fetch content. Different mitigations can lead to different kind of responses, which could explain the differences that users report.

Asking users to disable protections avoids the problem but doesn’t seem ideal if it can be avoided. It would be better if Cloudflare trusted the fetches from PWABuilder but that is an area beyond my expertise. As far as I understand the architecture, a human sits in the loop and triggers a centralised service to fetch the assets and do the bundling etc. An alternative might be to fetch the assets in the user’s browser and then post them to the centralised service for further processing.

2 Likes

Thanks, folks.

Interesting. So for this particular site, we’re actually seeing Cloudflare’s anti-bot tech causing the problem. I’m curious if that is the same issue of the many other sites we’ve seen with this problem. I’ll circle back if we find more details.

Obviously, Microsoft’s PWABuilder tool is not the kind of bot that Cloudflare is looking to block. We’re a good bot, one typically initiated by the owner of the site.

Short-term fix: what instructions can we give site owners to do to disable the anti-bot / CAPTCHA challenge in Cloudflare for our developer tooling?

Long-term fix: Could Cloudflare whitelist Microsoft’s PWABuilder tooling servers?

@judahgabriel if you haven’t already, can you submit a request to get PWABuilder set up as a verified bot here:

I’ll work with @LucasCF to get this flagged internally.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.