Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GM.xmlHttpRequest fails in Chrome with TypeError: Failed to construct 'Headers' Invalid value #162

Open
turkishmaid opened this issue Aug 11, 2024 · 8 comments

Comments

@turkishmaid
Copy link

turkishmaid commented Aug 11, 2024

Description

GM.xmlHttpRequest fails in Chrome with TypeError: Failed to construct 'Headers' Invalid value. It turns out that this piece of code splits a header string by \r\n while the header string h comes in with only \n as line separator:

var GM_fetch = (function () {
    'use strict';
  
    function parseRawHeaders(h) {
        const s = h.trim();
        if (!s) {
            return new Headers();
        }
        const array = s.split("\r\n").map((value) => {  
            let s = value.split(":");
            return [s[0].trim(), s[1].trim()];
        });
        return new Headers(array);
    }

Environment

  • MacOS 14.4 (23E214)
  • language version: Tampermonkey V5.2.3 in Chrome 127.0.6533.100 (arm64)
  • app/lib/repo version: 0.1.15

How to reproduce

const res = await GM_fetch("http://127.0.0.1:4711/test");

Expectations

Should deal with the headers as they come in, i.e. regardless whether it's \r\n (Brave 👍) or just \n (Chrome 🤦🏼‍♀️).
The following simple patch will do:

var GM_fetch = (function () {
    'use strict';
  
    function parseRawHeaders(h) {
        const s = h.trim().replace(/\r\n/g, '\n');          // patch
        if (!s) {
            return new Headers();
        }
        // const array = s.split("\r\n").map((value) => {   // original
        const array = s.split("\n").map((value) => {        // patch
            let s = value.split(":");
            return [s[0].trim(), s[1].trim()];
        });
        return new Headers(array);
    }

Should be here:

const array: [string, string][] = s.split("\r\n").map((value) => {

but I'm not the TypeScript expert to PR for that. In fact, I don't even have TS set up on my machine.

Actual result

GM.xmlHttpRequest fails with TypeError: Failed to construct 'Headers' Invalid value.

@trim21
Copy link
Owner

trim21 commented Aug 11, 2024

HTTP RFC says line break must be CRLF.

HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
protocol elements except the entity-body (see appendix 19.3 for
tolerant applications). The end-of-line marker within an entity-body
is defined by its associated media type, as described in section 3.7.

@trim21
Copy link
Owner

trim21 commented Aug 11, 2024

I'm using chrome on windows, which OS you are using?

Is this issue platform specific?

Or can you share server code to reproduce this? python/nodejs/go would be best.

@turkishmaid
Copy link
Author

turkishmaid commented Aug 12, 2024

HTTP RFC says line break must be CRLF

Absolutely! That's why I was using the respective emoticons above.

can you share server code

Unfortunately, no. It happens in userscript context in the browser. Let me give you a MVE to play with it yourself (use whatever URL you like for the GM_fetch, it will fail anyway):

// ==UserScript==
// @name         trim21
// @match        https://www.example.com/
// @require      https://cdn.jsdelivr.net/npm/@trim21/[email protected]/dist/gm_fetch.js
// @grant        GM.xmlHttpRequest
// @connect      *
// @run-at       document-end
// ==/UserScript==

await( async () => {
    'use strict';
    const url = "https://www.example.com";
    console.info(`will fetch ${url}`)
    // will fail with TypeError: Failed to construct 'Headers': Invalid value
    const res = await GM_fetch(url, {
        headers: { "content-type": "text/html" },
    });
    const text = await res.rawBody.text();
    console.info(text);
})();

Will break like so when you load https://www.example.com/:

162-3

162-4

You can see the value already in the debugger preview:

accept-ranges:bytes\nage:516377\ncache-control:max-age=
                  ====        ====

Nb.: It's the response headers, not the request headers, and it's completely independent from the URL you are fetching...

@turkishmaid
Copy link
Author

Oh, apologies, forgot the first question: I'm on MacOS 14.4 (23E214)...

@trim21
Copy link
Owner

trim21 commented Aug 12, 2024

It doesn't reproduce on windows. I think this is a upstream issue from Tampermonkey, can you also send a issue to them?

I can add a workaround on macos, but I think this should be fixed my Tampermonkey, since RFC says it's CRLF.

@trim21
Copy link
Owner

trim21 commented Aug 12, 2024

you can send a PR to add a workaround for MacOS only.

@subbotinb
Copy link

I have the same error on Windows with the latest version of Tampermonkey.

you can send a PR to add a workaround for MacOS only.
you can send a PR to add a workaround for MacOS only.

@trim21
Copy link
Owner

trim21 commented Sep 6, 2024

this should have been fixed by upstream Tampermonkey/tampermonkey#2160

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants