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

Request with GET/HEAD method cannot have body. #551

Closed
chrisrollins opened this issue Jun 12, 2017 · 41 comments
Closed

Request with GET/HEAD method cannot have body. #551

chrisrollins opened this issue Jun 12, 2017 · 41 comments

Comments

@chrisrollins
Copy link

chrisrollins commented Jun 12, 2017

I ran into this restriction while building HTTP functions for a library. I think this should be reconsidered because sometimes people actually use the body in a GET request. Notably, ElasticSearch can use it for queries. It can use the querystring instead, but that can be pretty cumbersome which is why it also accepts a body for GET queries.
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html

Since I'm making a library I want to allow everything within the specification of HTTP but apparently fetch has its own rules, and as you can see it's possible for that to interfere with using an API._

You'd think this is an edge case, but if it interferes with something like ElasticSearch maybe it's not an edge case._

@mnot
Copy link
Member

mnot commented Jun 18, 2017

HTTP allows a request body on GETs syntactically so that message parsing is generic; it doesn't say that a body has any meaning on a GET.

So, anyone using a body on a GET is effectively "off the reservation"; they're not longer using HTTP, but defining their own private protocol. Since Fetch is an API for HTTP, it's entirely reasonable for it not to allow this.

More practically, using bodies on GETs tends to trigger interop problems with proxies, CDNs, servers, etc. While it might work in the lab or even on the Internet under controlled conditions, using it at scale is very likely to bump into this. For example, users who have virus scanning proxies are likely to have problems, since they tend to have very conservative implementations.

@chrisrollins
Copy link
Author

chrisrollins commented Jun 18, 2017

Mark, thanks for your response.

This isn't about me or any individual wanting to use a body on a GET. It's about the fact that it is used in industry which you can see in the ElasticSearch documentation which I linked in my first post. ElasticSearch is used at scale in industry. Don't try to convince me not to use it. Convince people like Elastic company not to use it.

My point is, I don't think additional rules should be added to a spec even in parts where the spec isn't explicitly clear, especially when it can be shown that it limits certain industry applications.

@mnot
Copy link
Member

mnot commented Jun 18, 2017

If we changed how we use HTTP (or TCP, or any other protocol) to accommodate every abuse in "industry" like this, we'd quickly lose all of the value of having a shared protocol. Get them to fix their software, don't try to convince everyone else to accommodate their non-standard use.

@annevk
Copy link
Member

annevk commented Jun 22, 2017

Duplicate of #83. As far as I know nothing changed since then.

@annevk annevk closed this as completed Jun 22, 2017
@laddi
Copy link

laddi commented Feb 15, 2019

every abuse in "industry" like this

Doing something that is allowed within the HTTP spec is hardly abuse. It seems odd that the creators of this get to dictate how APIs should and should not work...

don't try to convince everyone else to accommodate their non-standard use

Well, you should take your own words to heart because what people are trying to accomplish is definitely according to standard...

@SmashingQuasar
Copy link

So far I could reference the following arguments against the addition (in fact it is a suppression) of this:

  • Semantics hardly matters and changing the way things work takes time: This is the point of a standard, being semantically correct and accurate. Everything takes time in our jobs. In my opinion this argument is totally invalid.
  • This can cause security issues because the body is sent silently (+ all other security concerns): This is a legit point to postpone the suppression of this but not to reject it all together. There is nothing impossible to fix about those security problems.
  • Some server (exaggerated originally as "most servers", which is wrong) do not support this: This shouldn't be a concern. If a server does not support this then most likely you can expect many other issues with this. It is most likely a server that just does not follow the RFC and does its own thing. A standard should not care about this use case.
  • There are alternatives like the POST method: Which is semantically incorrect thus shouldn't be promoted by a standard. The SEARCH method is definitely promising but I couldn't find any evidence supporting that will be implemented whatsoever. I would gladly be proven wrong on this last sentence since it would be a good addition that would probably solves this debate.

Please consider that all people that wrote messages about this concern aren't trolling or trying to enforce a point of view. Sending a GET Request with a body is used widely in the industry and is not explicitly forbidden by the RFC. Refusing to allow it for the reasons that I listed is just being conservative and reactionary. It does not promote progress in the slightest.

@rwlaschin
Copy link

Elasticsearch rest api requires sending a body with a GET. Please at least provide an option for disabling this. Sending a body with GET is part of the standard.

@Zamralik
Copy link

If some specific platforms/frameworks reject handling GET/HEAD requests with a body, those who use them will work around by making bodyless GET/HEAD requests or switching to standard compliant platforms/frameworks.

There are already platforms/frameworks handling GET/HEAD requests with a body, some of them also handle security and caching.

It isn't right to enforce non-standard behavior on the fetch API.
It forces the use/implementation of workarounds/hacks/middlewares to be standard compliant.

@annevk
Copy link
Member

annevk commented Mar 29, 2019

I recommend reading #83 for some background as to why this is not that simple. But really, if you can convince browsers to add this and overcome the hurdles discussed there, it'd happen. Advocacy here is unlikely to help with that though.

@annevk
Copy link
Member

annevk commented Mar 29, 2019

(Also, SEARCH works perfectly fine with fetch() in all browsers. You can even use CHICKEN as method if you want.)

@Zamralik
Copy link

@annevk
I had already read #83 before my previous answer.

Using a non-standard HTTP method is not an acceptable solution to a non-standard HTTP behavior.
Using non-standard HTTP methods go against the security/caching handling based on HTTP method.

Browsers follows the Fetch API standard, and suggesting otherwise is a bad call.
Browsers shouldn't be encouraged to not follow standards.
Noone wants to go back to the era when websites were made for specific browsers.

There is a HTTP standard. There is Fetch API standard.
Browsers should be compliant with the Fetch API standard.

Fetch API works using HTTP, so it should be compliant with HTTP standard unless it cause a security breach.
Security verification disallowing GET requests to have a body is not a concern for the standard.
There's no security imperative as GET requests are safe by nature (no modification).
If there's a security breach caused by a GET request, it's an implementation issue on the server, and should not be a concern for the standard as bad server implementations can exists for everything.

@chrisrollins
Copy link
Author

I recommend reading #83 for some background as to why this is not that simple. But really, if you can convince browsers to add this and overcome the hurdles discussed there, it'd happen. Advocacy here is unlikely to help with that though.

Can you be more specific about this? Which unique considerations are there for the browser application that makes it so difficult to allow this in the Fetch standard? I mean, keep in mind that if somebody really wants to send a GET with a body, they can do it with any other application. The issue with that is many developers want to implement internal tools as browser apps because it is convenient and safe.

@annevk
Copy link
Member

annevk commented Mar 29, 2019

It's as simple as allowing new things to be send to unsuspecting servers. Non-browser applications might not necessarily have the same state or run on the user's computer and therefore have access to the user's private network.

The bigger problem is lack of implementer interest though, as noted above.

@nnattawat
Copy link

I agreed with the fact that it is not really a standard way and fetch should not support it. For my case, I kind of need to get it done as an interim solution while 3rd party provider is making a change on their API. So I want to share the solution that I went with using node http module in case someone else is in the same situation as me.

import https from 'https';
import http from 'http';

const requestWithBody = (body, options = {}) => {
    return new Promise((resolve, reject) => {
        const callback = function (response) {
            let str = '';
            response.on('data', function (chunk) {
                str += chunk;
            });
            response.on('end', function () {
                resolve(JSON.parse(str));
            });
        };

        const req = (options.protocol === 'https:' ? https : http).request(options, callback);
        req.on('error', (e) => {
            reject(e);
        });
        req.write(body);
        req.end();
    });
};

// API call in async function
const body = JSON.stringify({ a: 1});
const result = await requestWithBody(body, options = {
        host: 'localhost',
        port: '3000',
        protocol: 'http:', // or 'https:'
        path: '/path',
        method: 'GET',
        headers: {
            'content-type': 'application/json',
            'Content-Length': body.length
        }
    };
)

@redeemefy
Copy link

redeemefy commented Jul 29, 2020

This might bring some clarity. Not that favors one side or the other but at least brings context to the conversation.
elastic/elasticsearch#16024

@SmashingQuasar
Copy link

From what I read in this issue and the associated comments, I see that the refusal is based on a theoretical vulnerability. I have put a great deal of thought about this but I fail to see how sending a body with a GET method can create a vulnerability? Could someone clarify this point with a concrete and reproducible example, please?

I also read the RFC again - and the comments on the Elasticsearch issue are pretty clear about that as well - I still fail to see where the RFC forbids to have a body using a GET method. It never states that anywhere from what I read. It only recommend using POST but there is no hard restriction. The RFC tends to be very clear about what is strictly forbidden and this is not the case.

@gibson042
Copy link

gibson042 commented Jan 14, 2021

httpwg/http-core#202 is something of a focal point for this conversation, and was resolved by updating the latest HTTP spec draft in httpwg/http-core@f34f677 to include the explanation you're asking for:

A client SHOULD NOT generate a body in a GET request. A payload received in a GET request has no defined semantics, cannot alter the meaning or target of the request, and might lead some implementations to reject the request and close the connection because of its potential as a request smuggling attack (Section 11.2 of [Messaging]).

It's not so much that HTTP clients are strictly forbidden from including content in a GET request, it's that HTTP servers may not use such content.

@Zamralik
Copy link

It's not so much that HTTP clients are strictly forbidden from including content in a GET request, it's that HTTP servers may not use such content.

So basically they're asking for people to bypass the standard completely and only use POST for everything just so they could use clean payloads without obstacles.

@J-Zeitler
Copy link

Just a question here, not advocating for any side in the debate :)

I'm a bit confused if this is a restriction in the Fetch specification or in Fetch implementations. If it's a spec thing, could someone point me to the relevant lines in https://fetch.spec.whatwg.org/? Tried to find what methods should support bodies but was unable to.

@Zamralik
Copy link

Rather than fix the implementation, they opted to subset the HTTP specification to fit the implementation of fetch().

Rule 33 of "The new Request(...) constructor steps are:" https://fetch.spec.whatwg.org/#dom-request

If either init["body"] exists and is non-null or inputBody is non-null, and request’s method is GET or HEAD, then throw a TypeError.

Which prevents doing clean call with complex nested structures like the fake code below.

const response = await fetch("/endpoint/search-something", {
    method: "GET",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        foo: {
            bar: "qux",
            qux: {
                bar: "foo"
            }
        }
    })
});

If you wanted to make a proper API to handle front & back interactions, you can't.

@einord
Copy link

einord commented Sep 22, 2021

So imagine if the fetch API added this capability to have a body with a GET request. It might not even work on some operating systems anyway, so browsers would be forced to not support it for the sake of consistency.

This is not true, it's the other way around.
If The Fetch API added this capability, browsers and other frameworks would have to start supporting it eventually. Yes, it would be a somewhat painful time at first, but not more painful than it currently is now limiting peoples applications for arbitrary reasons.

@Zamralik
Copy link

So imagine if the fetch API added this capability to have a body with a GET request. It might not even work on some operating systems anyway, so browsers would be forced to not support it for the sake of consistency.

This is not true, it's the other way around.
If The Fetch API added this capability, browsers and other frameworks would have to start supporting it eventually. Yes, it would be a somewhat painful time at first, but not more painful than it currently is now limiting peoples applications for arbitrary reasons.

Exact !

What we can be certain of is that browsers, OS, proxies, ... will never bother implementing something that is explicitly forbidden by the standard.

The way it works is :

  1. Standard says something is fine
  2. It is slowly implemented on some products
  3. It's implemented enough that it become used with a polyfill/compatibility wrapper
  4. As it is more and more used, it gets implemented on every products
  5. It is used raw without a polyfill/compatibility wrapper

Being allowed by the standard is the first step.

The only reverse situation is when you have a step 0)
=> A nice missing feature that is not mentioned in the standard is added to some products

But it will never happen if that feature is forbidden by the standard.

@SmashingQuasar
Copy link

Also, the Fetch API (and thus the DOM API overall) is establishing the standard for browsers. It's not up to browsers to determine if they feel like implementing it or not. If they don't, then they will fall behind technologically speaking and will end up like Internet Explorer.
The more I read this discussion, the more it looks like a dogma than an objective approach to this problem.

@cliffordfajardo
Copy link

cliffordfajardo commented Aug 27, 2022

I tried using fetch and node-fetch to make GET with a request body, but it fails with:

Request with GET/HEAD method cannot have body

Workaround for Nodejs runtimes (not in browser ... JS on the server)

Unfortunately the API I'm working with I cannot change at this time so I needed a work around.
You can use the axios library to make GET with request body's

// only works in node / server -- i have not tried in the browser
const res = await axios.get("/api/devices", { 
  data: { deviceName: 'name' } 
}) 

@chrisrollins
Copy link
Author

I tried using fetch and node-fetch to make GET with a request body, but it fails with:

Request with GET/HEAD method cannot have body

Workaround for Nodejs runtimes (not in browser ... JS on the server)

Unfortunately the API I'm working with I cannot change at this time so I needed a work around. You can use the axios library to make GET with request body's

// only works in node / server -- i have not tried in the browser
const res = await axios.get("/api/devices", { 
  data: { deviceName: 'name' } 
}) 

It will not work in browser because the available APIs don't allow it.

Also note that on some operating systems it won't work because the underlying HTTP implementation does not allow it. IIRC that includes iOS and Windows.

In theory you could implement an HTTP client from scratch using lower level network APIs and guarantee the ability to have a body in GET requests... But still can't do this in browser because such low level APIs are not available.

@bediu
Copy link

bediu commented May 30, 2023

Every time I encounter a GET endpoint in the wild that accepts a body, I get reminded that this thread exists and there is not a single post here with an objective reason why GET shouldn't have a body.

@alex-h-strachan
Copy link

Every time I encounter a GET endpoint in the wild that accepts a body, I get reminded that this thread exists and there is not a single post here with an objective reason why GET shouldn't have a body.

More frustrating the language change on the HTTP spec to say "should not" was supposed to be accompanied by a new method SEARCH that would explicitly allow a body.

Right now we're in a situation where the best practice for when your query params on a GET get too long are to... convert it to a semantically incorrect POST, use a nonstandard method SEARCH or fight with creating something standard compliant in HTTP but that errors if anyone tries to use FETCH.

@SmashingQuasar
Copy link

Every time I encounter a GET endpoint in the wild that accepts a body, I get reminded that this thread exists and there is not a single post here with an objective reason why GET shouldn't have a body.

More frustrating the language change on the HTTP spec to say "should not" was supposed to be accompanied by a new method SEARCH that would explicitly allow a body.

Right now we're in a situation where the best practice for when your query params on a GET get too long are to... convert it to a semantically incorrect POST, use a nonstandard method SEARCH or fight with creating something standard compliant in HTTP but that errors if anyone tries to use FETCH.

The language change was only due to the WHATWG not wanting to admit they made a mistake so the standard got modified instead. There is nothing more to it.

@LeonardoDaLuz
Copy link

The RFC should be changed, everyone needs it. I need to make complex queries, so I need to use methods other than GET, does not make sense... Whoever takes care of this RFC doesn't know what the programmer suffers.

@Zamralik
Copy link

Zamralik commented Oct 7, 2023

The RFC should be changed, everyone needs it. I need to make complex queries, so I need to use methods other than GET, does not make sense... Whoever takes care of this RFC doesn't know what the programmer suffers.

At the very least, the standard should add new alternative standard verbs that are similar to GET and HEAD in meaning, but support having a body.

@james-bowers
Copy link

At the very least, the standard should add new alternative standard verbs that are similar to GET and HEAD in meaning, but support having a body.

Including a body in a GET request, is already supported in the standard

@Zamralik
Copy link

At the very least, the standard should add new alternative standard verbs that are similar to GET and HEAD in meaning, but support having a body.

Including a body in a GET request, is already supported in the standard

Indeed it is, but the whatwg seems hellbent in stubornly rejecting that standard use because it could mess up with legacy code that assume otherwise.

Hence why the least would be to do the same thing that was done with HTTP, when codes 307/308 were added as alternative to 301/302.

@bediu
Copy link

bediu commented Oct 13, 2023

Indeed it is, but the whatwg seems hellbent in stubornly rejecting that standard use because it could mess up with legacy code that assume otherwise.

Legacy code assuming get requests use no body, would not use body in their get requests. So how is supporting body for get requests going to break legacy code?

@Zamralik
Copy link

Legacy code assuming get requests use no body, would not use body in their get requests. So how is supporting body for get requests going to break legacy code?

Their reasonning is that some caching systems could cache the response ignoring the body when making an identifier rather than a using a hash of the full request with the body too. And they consider that to be enough to then edit the fetch() standard to forbid a body with HEAD/GET.

@cscawley
Copy link

cscawley commented Dec 8, 2023

I guess I'll just use a POST when I want to retrieve entities based on structured data. Thanks guys. Doing good work over here👍

@Zamralik
Copy link

Zamralik commented Dec 18, 2023

There is a decade old draft for QUERY, an equivalent of GET with a body. It's barely touched upon. From time to time it's brought back from the bin.

Current draft
https://httpwg.org/http-extensions/draft-ietf-httpbis-safe-method-w-body.html

Timeline
https://datatracker.ietf.org/doc/draft-ietf-httpbis-safe-method-w-body/

@tranvansang
Copy link

curl allows get with a body. Now I HAVE TO switch from fetch to another library because fetch does not allow this.

It is not my fault, it is the server's fault, and I cannot change how the server works.

@mitar
Copy link

mitar commented Apr 24, 2024

Now I HAVE TO switch from fetch to another library because fetch does not allow this.

A library for the browser? I do not think any can support that if fetch does not.

@tranvansang
Copy link

tranvansang commented Apr 24, 2024

library like axios use xmlrequest, does not rely on fetch.

@SmashingQuasar
Copy link

Now I HAVE TO switch from fetch to another library because fetch does not allow this.

A library for the browser? I do not think any can support that if fetch does not.

You can easily circumvent fetch by relying on XMLHTTPRequest.

@sheecegardezi
Copy link

this has not been fixed ... I cant send body using get method using fetch ... thank you so much for the lessons on fake security ... now please enable sending body through get request.

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

No branches or pull requests