2020 EDIT:
I keep seeing this get commented on and referenced so let me share some new information that I have learned since I made this issue. I am editing this in before my original post because I want high visibility.
From some recent experiences I learned that a lot of underlying HTTP client implementations (think OS level) will either silently remove the body or throw an error. Therefore I recommend against ever putting a body in a GET request.
I tested some HTTP client code on Windows and it seemed fine, then I ran the same code on a Xamarin app on Android. The API server rejected the same request when it came from my app. It turned out my code was putting an empty body in my GET requests (my bad) but the underlying Windows implementation under the .NET code was silently removing it. On Android this was not happening, and it happened that the API server I was interacting with was set up to reject if a GET request had a body.
I am now working on a mobile app we had an issue when Apple updated iOS recently. Now their HTTP client implementation throws an error if the GET request has a body. Some of our legacy code was sending an empty body and this became an issue we had to fix because of the OS update.
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.
I think it is unfortunate but a lot of libraries and low level APIs have various opinions built into them.
Original post:
_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._
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.
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.
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.
Duplicate of #83. As far as I know nothing changed since then.
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...
So far I could reference the following arguments against the addition (in fact it is a suppression) of this:
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.
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.
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.
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.
(Also, SEARCH works perfectly fine with fetch() in all browsers. You can even use CHICKEN as method if you want.)
@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.
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.
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.
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
}
};
)
This might bring some clarity. Not that favors one side or the other but at least brings context to the conversation.
https://github.com/elastic/elasticsearch/issues/16024
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.
httpwg/http-core#202 is something of a focal point for this conversation, and was resolved by updating the latest HTTP spec draft in https://github.com/httpwg/http-core/commit/f34f6774ea79b04ece75fdaeb8f5246371ad0729 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.
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.
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.
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鈥檚 method is
GETorHEAD, 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.
Most helpful comment
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...
Well, you should take your own words to heart because what people are trying to accomplish is definitely according to standard...