Correct behavior with If-Match the header? - http

According to RFC 2616, generation of entity tags by HTTP servers is optional. However, I couldn't find what a conditionally compliant HTTP server should do if it receives an If-Match (or If-None-Match) header. Should it just ignore those headers or should it respond with 412 Precondition Failed?
UPD: Just to clarify, I'm assuming that the server in question does not support entity tags.

In contrast to an If-None-Match header (ignorance of which only harms performance), an IF-MATCH request should almost certainly fail and return a HTTP/412 if the server cannot match the requested entity. Probably the most common use of the IF-MATCH header is when the client is doing a Range request, and unless the server can confirm that the resource was not modified, it should not return the requested range because the result could be data corruption on the client.
Now, if the server knows it's not a Range request or knows that the client entity must, in fact, match (e.g. because the server never allows updates to its entities) then acting as if the header wasn't present may make sense in that limited circumstance.

There is a handy HTTP response status codes activity diagram that you can use to answer this question.
If you don’t support ETag and the request contains a If-Match value other than *, you would respond with a 412. And If-None-Match with values other than * can be completely ignored.

While the RFC2616 is implicit on the matter, you can deduce from, say 14.26 (If-None-Match), that if the server cannot match the resource with the tag, then it should go ahead with request). The 412 code, based upon my understanding of RFC2616 is intended for requests which modify state (e.g. PUT, POST, DELETE).
So, in essence, if the tag doesn't match (and when it's absent on server side is only one of many possible scenarios), then the server should go ahead with the request.

Related

HTTP Status Code Priority and Processing

Let's say a web application gets the following request:
POST /some/endpoint HTTP/1.1
Host: <something>
Accept: application/json
Accept-Language: pt
Content-Type: application/json
If-Match: "blabla"
Some body
If the server doesn't support HTTP 1.1 and the endpoint /some/endpoint does not exist, the former problem should likely be checked first, and a 505 rather than 404 should be returned.
If it just so happens that none of the endpoints of the server accept POST and the endpoint /some/endpoint doesn't exist, the latter should get priority, and 404 should be returned rather than 405.
If the Accept can't be provided and the body can't be appropriately decoded/validated, probably 406 should take precedence over 400.
These are cases where intuition might suffice. But there are a myriad other ones where it is not clear which of two non-2XX status codes should be preferred/checked first. For example, should Content-Type (resulting in 415) or Accept-Language (406) be returned if both would fail? 415 or 412? And on it goes...
Much of the time errors are pairwise independent: if the aspect that is relevant to one error being thrown (such as a particular header value) is fixed, the success/error status of another will not be affected. In those cases, the wrong error "priority" is perhaps only a nuisance. But sometimes it may be the case that these errors are not independent: I might have a resources as HTML in Portuguese, but in JSON only in English (humour me), so that if a client expects me to prioritise Accept-Language over Accept, and I do the opposite, the result will be quite bad.
The question should be evident now: are there any standards about which errors should be prioritised?
I haven't come across any relevant RFCs, or even much serious and general discussion. I know of the webmachine diagram, which sort of helps, but primarily just seems to describe a particular (well thought out) implementation rather than any standard.
Obviously, you can’t expect this question to be answered “no,” even though that’s probably the correct answer.
So let me address a particular point of yours instead:
I might have a resources as HTML in Portuguese, but in JSON only in English (humour me), so that if a client expects me to prioritise Accept-Language over Accept, and I do the opposite, the result will be quite bad.
In your example, you tell the server that Portuguese JSON is good, but all other combinations are equally bad. If that’s not the case, you can elaborate your preferences like this:
Accept: text/json
Accept-Language: pt, en;q=0.1
The server can then multiply your weights, getting 1×0.1=0.1 for English JSON and 0×1=0 for Portuguese HTML, and choosing the former.
(Sidenote 1: there is no text/json media type in the registry. You probably want application/json.)
(Sidenote 2: 415 Unsupported Media Type is not a correct response code for the scenarios you mention. It concerns the request body. If you cannot honor the Accept header, you can respond with 406 Not Acceptable, just as with Accept-Language.)
TL;DR: The specifications give the server ultimate authority in how it honors the request, even allowing the server to ignore the acceptable formats the client requests. However, the specifications instruct the server to make a best effort and to respond in a way that best helps the client recover from errors.
The specifications provide guidance, even if they don't (or can't) prioritize all possible error modes.
RFC 2616 § 10.4.7 says:
HTTP/1.1 servers are allowed to return responses which are
not acceptable according to the accept headers sent in the
request. In some cases, this may even be preferable to sending a
406 response. User agents are encouraged to inspect the headers of
an incoming response to determine if it is acceptable.
RFC 7231 § 3 says:
An origin server might be provided with, or be capable of generating,
multiple representations that are each intended to reflect the
current state of a target resource. In such cases, some algorithm is
used by the origin server to select one of those representations as
most applicable to a given request, usually based on content
negotiation.
RFC 7231 § 3.4 says:
Note that, in all cases, HTTP is not aware of the resource semantics.
The consistency with which an origin server responds to requests ... is determined entirely by whatever entity or algorithm selects
or generates those responses. HTTP pays no attention to the man
behind the curtain.
RFC 7231 § 3.3 says:
Response messages with an error status code
usually contain a payload that represents the error condition, such
that it describes the error state and what next steps are suggested
for resolving it.
RFC 2616 § 14.46 says:
The Warning general-header field is used to carry additional information about the status or transformation of a message which might not be reflected in the message. This information is typically used to warn about a possible lack of semantic transparency from caching operations or transformations applied to the entity body of the message.
(Emphases all mine.)
Section 3 of RFC 7231 gives the origin server ultimate authority to decide the appropriate response, even if that response is repugnant. Simultaneously, section 3 encourages the origin server to satisfy the request, or provide notice that it satisfied some of the request (Vary), or provide selectable options ("Passive negotiation").
Even though the server has ultimate authority, the specification makes clear to me that the responses should help the user resolve the problem. In my mind, the best error code is the one that helps the user best fix the problem!
Considering your pair-wise examples:
"If the server doesn't support HTTP 1.1 and the endpoint /some/endpoint does not exist, the former problem should likely be checked first, and a 505 rather than 404 should be returned."
No. Per the spec, an HTTP 1.1 client can GET from 1.0 server by protocol downgrade, so this kind of version negotiation is handled by the specification. Send a 404 (or a 301 if that's known) so the user can correct it.
"If it just so happens that none of the endpoints of the server accept POST and the endpoint /some/endpoint doesn't exist, the latter should get priority, and 404 should be returned rather than 405."
Yes, 404. If you're not getting to a resource, the method hardly matters.
"If the Accept can't be provided and the body can't be appropriately decoded/validated, probably 406 should take precedence over 400."
Never send 400 when you know 406 applies. You're giving the client less information, which is less helpful. However, the origin server is free to ignore the Accept header per RFC 7231 § 5.3.2:
If the [Accept] header field is
present in a request and none of the available representations for
the response have a media type that is listed as acceptable, the
origin server can either honor the header field by sending a 406 (Not
Acceptable) response or disregard the header field by treating the
response as if it is not subject to content negotiation.
"I might have a resources as HTML in Portuguese, but in JSON only in English (humour me), so that if a client expects me to prioritise Accept-Language over Accept, and I do the opposite, the result will be quite bad."
I disagree that the result will be bad. See RFC 7231 § 5.3.5:
the origin server can either disregard the [Accept-Language] header field by treating the response as if it is not subject to content negotiation or honor the header field by sending a 406 (Not Acceptable) response. However, the latter is not encouraged, as doing so can prevent users from accessing content that they might be able to use (with translation software, for example).
This pattern of specification language occurs more than once. "The server may disregard [whatever the client requested] by treating the response as if it's not subject to [this part of the specification], or the server may honor [the client request] and send [an applicable error code]. But, it's better to [send something intelligible] than only send [an inscrutable error code]."
At the end of the day, it's your API. HTTP provides only a window into your semantics. Document what you accept, how you respond, and with what. Send intelligible responses (HATEOAS is good) and, when applicable, the most specific error codes available.

Is absence of If-Match or If-Not-Match header shall be treated as unconditional request?

HTTP 1.1 spec has clear definition of server behavior if one of them is present. In my case, I have two clients, one old and one new. Old client ignores etag in response, and sends put request without etag; new client uses the If-Match + etag in put request. My understanding is that server shall take put request without If-Match as unconditional request and proceed. However, the consequence of it is that without etag, old client might do put request based on old data. So I have the question in Titie, "Is absence of If-Match or If-Not-Match header shall be treated as unconditional request?"
Well. A request is unconditional when it doesn't have any conditions attached to it. The base set of conditional request header fields is defines in http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p4-conditional-25.html, extension specs such as WebDAV add more.
Whether the server actually accepts the unconditional request is another story, see http://greenbytes.de/tech/webdav/rfc6585.html#status-428.

Compare-and-swap for HTTP PUT?

Is there a way to make a compare-and-swap-style mechanism the only way to modify certain resources, whilst following the HTTP standard?
There's an If-Match header which implements the correct behaviour however this header is optional: as far as I can tell, if If-Match is not provided, the server should honour the PUT. (That is, it's up to the client to decide whether it wants to compare-and-swap, or just swap.) Would it be acceptable to respond with 412 Precondition Failed if the client tries to PUT or POST without providing an If-Match header?
No, but you can use status code 428 Precondition Required (see http://greenbytes.de/tech/webdav/rfc6585.html#status-428).

Should HTTP Client parse HTTP Headers in response with the error 404 Not Found

I cannot find any RFC or Standard of HTTP client behavior in case it gets HTTP response with an error 4xx. I know the 401, 407 are the examples when the HTTP headers are parsed, but...
I have the concrete problem for OPTIONS method (HTTP1.1). The server responses 401 Unauthorized, so client tries to authenticate and re-sends the request with an authentication. After that the response has the error 404 Not Found and HTTP header is filled with Set-Cookie HTTP Header. The client use Apache Java HTTPClient/HTTPComponents, which ignores HTTP headers in case of an error in the response.
Should this HTTP Header be accepted by the client? I believe it should not be, but I cannot find the supportive quotation in the RFC.
RFC 2616 does not specify that any headers should be ignored, not for 404 responses and not for 4xx responses in general either.
RFC 6265 allows clients to ignore Set-Cookie headers, but does not specify situations where that might happen; a single example is given, that does not cover your case:
the user agent might wish to block responses to "third-party" requests
from setting cookies
In your case, since your server seems to use HTTP basic access authentication, it does not seem to concern the Set-Cookie header. In HTTP basic authentication, the Authorization header is sent by the client with every request, so there should be no need to keep state in a cookie.
It is not clear from your question if you have a very specific HTTP server that you're talking to, or if you are implementing a general HTTP client that is supposed to work with whatever server you throw it at. If you have such a specific case that the HTTP server you work with sends state with 404 responses, and you're required to honor that state in order to communicate with the server, and you have no control over the server, then it does not matter what the standard says; you will honor the state sent, or you will not be able to talk to the server.
If, on the other hand, you're implementing a general client and need it to work regardless of the remote server, then your best bet is to stick to RFC 1958:
Be strict when sending and tolerant when receiving.
Implementations must follow specifications precisely when sending to
the network, and tolerate faulty input from the network. When in
doubt, discard faulty input silently, without returning an error
message unless this is required by the specification.
Which, to me, would mean that you should honor the full response received, regardless of the status code, unless you have an objective reason making it impossible for you to do so. I don't see a reason to ignore the state, even if it violates the standard (or in this case, your personal perception of the standard, since it does not say anything about accepting or ignoring the state).
Update: RFC 2617 (HTTP Authentication) states:
A client SHOULD assume that all paths at or deeper than the depth of
the last symbolic element in the path field of the Request-URI also
are within the protection space specified by the Basic realm value of
the current challenge. A client MAY preemptively send the
corresponding Authorization header with requests for resources in
that space without receipt of another challenge from the server.
It is highly inconsistent if the server expects HTTP authentication for one URL, but does not honor it for URLs beneath it, requiring a separate cookie-based authentication for them. If anything should be changed in your server implementation, it should be to harmonize the authentication scheme for all resources.

Is an entity body allowed for an HTTP DELETE request?

When issuing an HTTP DELETE request, the request URI should completely identify the resource to delete. However, is it allowable to add extra meta-data as part of the entity body of the request?
The spec does not explicitly forbid or discourage it, so I would tend to say it is allowed.
Microsoft sees it the same way (I can hear murmuring in the audience), they state in the MSDN article about the DELETE Method of ADO.NET Data Services Framework:
If a DELETE request includes an entity body, the body is ignored [...]
Additionally here is what RFC2616 (HTTP 1.1) has to say in regard to requests:
an entity-body is only present when a message-body is present (section 7.2)
the presence of a message-body is signaled by the inclusion of a Content-Length or Transfer-Encoding header (section 4.3)
a message-body must not be included when the specification of the request method does not allow sending an entity-body (section 4.3)
an entity-body is explicitly forbidden in TRACE requests only, all other request types are unrestricted (section 9, and 9.8 specifically)
For responses, this has been defined:
whether a message-body is included depends on both request method and response status (section 4.3)
a message-body is explicitly forbidden in responses to HEAD requests (section 9, and 9.4 specifically)
a message-body is explicitly forbidden in 1xx (informational), 204 (no content), and 304 (not modified) responses (section 4.3)
all other responses include a message-body, though it may be of zero length (section 4.3)
Update
And in RFC 9110 (June 2022), The fact that request bodies on GET, HEAD, and DELETE are not interoperable has been clarified.
section 9.3.5 Delete
Although request message framing is independent of the method used,
content received in a DELETE request has no generally 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 [HTTP/1.1]). A client SHOULD NOT generate content in
a DELETE request unless it is made directly to an origin server that
has previously indicated, in or out of band, that such a request has a
purpose and will be adequately supported. An origin server SHOULD NOT
rely on private agreements to receive content, since participants in
HTTP communication are often unaware of intermediaries along the
request chain.
The 2014 update to the HTTP 1.1 specification (RFC 7231) explicitly permits an entity-body in a DELETE request:
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
Some versions of Tomcat and Jetty seem to ignore a entity body if it is present. Which can be a nuisance if you intended to receive it.
One reason to use the body in a delete request is for optimistic concurrency control.
You read version 1 of a record.
GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }
Your colleague reads version 1 of the record.
GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }
Your colleague changes the record and updates the database, which updates the version to 2:
PUT /some-resource/1 { id:1, status:"important", version:1 }
200 OK { id:1, status:"important", version:2 }
You try to delete the record:
DELETE /some-resource/1 { id:1, version:1 }
409 Conflict
You should get an optimistic lock exception. Re-read the record, see that it's important, and maybe not delete it.
Another reason to use it is to delete multiple records at a time (for example, a grid with row-selection check-boxes).
DELETE /messages
[{id:1, version:2},
{id:99, version:3}]
204 No Content
Notice that each message has its own version. Maybe you can specify multiple versions using multiple headers, but by George, this is simpler and much more convenient.
This works in Tomcat (7.0.52) and Spring MVC (4.05), possibly w earlier versions too:
#RestController
public class TestController {
#RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
SomeBean echoDelete(#RequestBody SomeBean someBean) {
return someBean;
}
}
Just a heads up, if you supply a body in your DELETE request and are using a google cloud HTTPS load balancer, it will reject your request with a 400 error. I was banging my head against a wall and came to found out that Google, for whatever reason, thinks a DELETE request with a body is a malformed request.
Roy Fielding on the HTTP mailing list clarifies that on the http mailing list https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html and says:
GET/DELETE body are absolutely forbidden to have any impact whatsoever
on the processing or interpretation of the request
This means that the body must not modify the behavior of the server.
Then he adds:
aside from
the necessity to read and discard the bytes received in order to maintain
the message framing.
And finally the reason for not forbidding the body:
The only reason we didn't forbid sending a body is
because that would lead to lazy implementations assuming no body would
be sent.
So while clients can send the payload body, servers should drop it
and APIs should not define a semantic for the payload body on those requests.
It appears to me that RFC 2616 does not specify this.
From section 4.3:
The presence of a message-body in a request is signaled by the
inclusion of a Content-Length or Transfer-Encoding header field in
the request's message-headers. A message-body MUST NOT be included in
a request if the specification of the request method (section 5.1.1)
does not allow sending an entity-body in requests. A server SHOULD
read and forward a message-body on any request; if the request method
does not include defined semantics for an entity-body, then the
message-body SHOULD be ignored when handling the request.
And section 9.7:
The DELETE method requests that the origin server delete the resource
identified by the Request-URI. This method MAY be overridden by human
intervention (or other means) on the origin server. The client cannot
be guaranteed that the operation has been carried out, even if the
status code returned from the origin server indicates that the action
has been completed successfully. However, the server SHOULD NOT
indicate success unless, at the time the response is given, it
intends to delete the resource or move it to an inaccessible
location.
A successful response SHOULD be 200 (OK) if the response includes an
entity describing the status, 202 (Accepted) if the action has not
yet been enacted, or 204 (No Content) if the action has been enacted
but the response does not include an entity.
If the request passes through a cache and the Request-URI identifies
one or more currently cached entities, those entries SHOULD be
treated as stale. Responses to this method are not cacheable.c
So it's not explicitly allowed or disallowed, and there's a chance that a proxy along the way might remove the message body (although it SHOULD read and forward it).
I don't think a good answer to this has been posted, although there's been lots of great comments on existing answers. I'll lift the gist of those comments into a new answer:
This paragraph from RFC7231 has been quoted a few times, which does sum it up.
A payload within a DELETE request message has no defined semantics;
sending a payload body on a DELETE request might cause some existing
implementations to reject the request.
What I missed from the other answers was the implication. Yes it is allowed to include a body on DELETE requests, but it's semantically meaningless. What this really means is that issuing a DELETE request with a request body is semantically equivalent to not including a request body.
Including a request body should not have any effect on the request, so there is never a point in including it.
tl;dr: Techically a DELETE request with a request body is allowed, but it's never useful to do so.
Using DELETE with a Body is risky... I prefer this approach for List Operations over REST:
Regular Operations
GET /objects/ Gets all Objects
GET /object/ID Gets an Object with specified ID
POST /objects Adds a new Object
PUT /object/ID Adds an Object with specified ID, Updates an Object
DELETE /object/ID Deletes the object with specified ID
All Custom actions are POST
POST /objects/addList Adds a List or Array of Objects included in body
POST /objects/deleteList Deletes a List of Objects included in body
POST /objects/customQuery Creates a List based on custom query in body
If a client doesn't support your extended operations they can work in the regular way.
It is worth noting that the OpenAPI specification for version 3.0 dropped support for DELETE methods with a body:
see here and here for references
This may affect your implementation, documentation, or use of these APIs in the future.
It seems ElasticSearch uses this:
https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api
Which means Netty support this.
Like mentionned in comments it may not be the case anymore
Several other answers mention RFC 7231 which had effectively said that a DELETE request is allowed to have a body but it is not recommended.
In 2022, RFC 7231 was superseded by RFC 9110: HTTP Semantics, which now says:
[...] content received in a DELETE request has no generally defined semantics, cannot alter the meaning or target of the request, and might lead some implementations to reject the request and close the connection [...]. A client SHOULD NOT generate content in a DELETE request unless it is made directly to an origin server that has previously indicated, in or out of band, that such a request has a purpose and will be adequately supported. An origin server SHOULD NOT rely on private agreements to receive content, since participants in HTTP communication are often unaware of intermediaries along the request chain.
This language has been strengthened from the previous language, to say that even though it is allowed, you really need to be very careful when using it because (for example) some users might be behind a proxy that would strip the body from the request in order to combat "request smuggling".
In case anyone is running into this issue testing, No, it is not universally supported.
I am currently testing with Sahi Pro and it is very apparent a http DELETE call strips any provided body data (a large list of IDs to delete in bulk, as per endpoint design).
I have been in contact with them several times, also sent three separate packages of scripts, images and logs for them to review and they still have not confirmed this. A failed patch, and a missed conference calls by their support later and I still haven't gotten a solid answer.
I am certain Sahi does not support this, and I would imagine many other tools follow suite.
This is not defined.
A payload within a DELETE request message has no defined semantics;
sending a payload body on a DELETE request might cause some existing
implementations to reject the request.
https://www.rfc-editor.org/rfc/rfc7231#page-29
Practical answer: NO
Some clients and servers ignore or even delete the body in DELETE request. In some rare cases they fail and return an error.
Might be the below GitHUb url will help you, to get the answer.
Actually, Application Server like Tomcat, Weblogic denying the HTTP.DELETE call with request payload. So keeping these all things in mind, I have added example in github,please have a look into that
https://github.com/ashish720/spring-examples

Resources