HTTP Status Code for Resource not yet available - http

I have a REST endpoint accepting a POST request to mark a code as redeemed. The code can only be redeemed between certain dates.
How should I respond if someone attempts to redeem the code early?
I suspect HTTP 403, Forbidden, is the right choice but then the w3c states that "the request SHOULD NOT be repeated" whereas in this case I would anticipate the request being repeated, just at a later date.

409 Conflict
The request could not be completed due to a conflict with the current
state of the resource. This code is only allowed in situations where
it is expected that the user might be able to resolve the conflict and
resubmit the request. The response body SHOULD include enough
information for the user to recognize the source of the conflict.
Ideally, the response entity would include enough information for the
user or user agent to fix the problem; however, that might not be
possible and is not required.
403 Forbidden makes more sense if they are trying to redeem a coupon that has already been redeemed, though 410 Gone seams elegant in this situation as well.
404 Not Found isn't ideal because the resource does in fact exist, however you can use it if you don't want to specify a reason with the 403 or if you want to hide the existence of the resource for security reasons.
If you are using HATEOAS, then you can also head you clients off at the pass (so to speak) by only including a redeem hypermedia control in the coupon resource (retrieved via a GET) when the coupon can be redeemed; though this won't stop overly bound clients from trying to redeem it anyway.

EDIT: Thanks to some good critiques (see below), I want to caveat this answer. It is based on Richardson & Ruby's writeup, which arguably doesn't mesh well with the httpbis writing on 403 Forbidden. (Personally, now I'm learning towards 409 as explained by Tom in a separate answer.)
403 Forbidden is the best choice. I will cite RESTful Web Services by Richardson & Ruby line by line. As you will see, 403 is a great fit:
The client's request is formed correctly, but the server doesn't want to carry it out.
Check!
This is not merely the case of insufficient credentials: that would be a 401 ("Unauthorized"). This is more like a resource that is only accessible at certain times, or from certain IP addresses.
Check!
A response of 403 implies that the client requested a resource that really exists. As with with 401 ("Unauthorized"), if the server doesn't want to give out even this information, it can lie and send a 404 ("Not Found") instead.
You wrote above: "The Code representation is available to be GETted before it goes live." So, you aren't trying to hide anything. So, stick with the 403. Check!
If the client's request is well-formed, why is this status code in the 4xx series (client-side error) instead of the 5xx series (server-side error)? Because the serve made it decision based on some aspect of the request other than its form; say, the time of day the request was made.
Check! The client's request was formed corrected, but it was inappropriate for the particular time.
We went four for four. The 403 code is a winner. No other codes match as well.
All of this said, a plain, non-specific 400 wouldn't be wrong, but would not be as specific or useful.
Another answer suggested the 409 Conflict code. Although worth considering, it isn't as good a fit. Here is why. According to Richardson & Ruby again:
Getting this [409] response response means that you tried to put the server's resources into an impossible or inconsistent state. Amazon S3 gives this response code when you try to delete a bucket that is not empty.
Claiming a promotion before it is 'active' wouldn't "put a server resource into an inconsistent state." It would break some business rules -- and result in cheating -- but it wouldn't cause a logical contradiction that I see.
So, whether you realized it at the onset of asking your question or not, 403 is a great choice. :)

Since Rest URLs should represent resources I would reply with 404 - Not Found
The resource is only available between certain dates, so on any other date it is not found.

When it says the request "SHOULD NOT be repeated", it is referring to the message that you should send to the viewer.
It has nothing to do with whether an actual request is repeated. (The user will get the same 403 message over and over again if s/he so desires.)
That said, a 404 is not appropriate for this because the resource is available - just that the code is not redeemable/forbidden to redeem. It is actually harmful because it tells the user that you probably made a mistake in your URL link or server configuration.
Of course, this assumes that on the appropriate date you return a 200 instead.

Related

Should I deny unused request methods?

In my Zend Framework MVC application I am using only two request methods: GET and POST. I am wondering whether I should put a check in my base controller to throw an exception if the other request types are received (e.g. PUT or DELETE).
As far as I can see there are two areas for consideration:
Would it improve security at all? Am I giving potential hackers a head start if I allow the framework to respond to PUT, DELETE, et al?
Would it interfere with correct operation of the site? For example, do search engine bots rely on requests other than GET and POST?
Your ideas are much appreciated!
The correct response code would be 405 Method Not Allowed, including an Allow: GET, POST header.
10.4.6 405 Method Not Allowed
The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response MUST include an Allow header containing a list of valid methods for the requested resource.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
People violate the api of your app/framework/site etc either due to errors or on purpose, to probe your site for weaknesses. (Only matters in frequency if your site is internal only or on the public net.)
If your site supports developers, then that'd be a possible reason to reply with a 405 code of method not allowed. Perhaps only if the session (assuming sessions) is marked as being in developer mode.
If you don't expect valid developers, then I recommend silently swallowing any bad input to make it harder for the bad guys.
Another reason not to give error messages in the normal case: the lack of an error message in a particular case can then be interpreted that the bad data made it further into your stack than other data--outlining a possible attack route.
And finally, error returns (type, delay before responding, and more) can be used to characterize a particular version of an app/framework etc. This can then be used to quickly locate other vulnerable installations once an attack vector is found.
Yes, the above is pessimistic, and I fondly remember the 80's when everybody responded to ping, echo and other diagnostic requests. But the bad guys are here and it is our responsibility to harden our systems. See this TED video for more.

What is the most appropriate HTTP response code for a resource known NOT to exist?

I wonder if there is a better choice than 404 when someone requests a page like http://www.example.com/page-that-never-existed-nor-will-ever-exist ("ever" meaning for the foreseeable future but for all intents and purposes: never ever).
For instance I get requests for pages that some "clever" crawlers think might exist based on the structure they have encountered on the website or elsewhere on the web. They are not misspellings but requests that I know to lead nowhere
I don't want to use 301 Moved Permanently because nothing has moved and there is no logical destination to move to.
I don't want to use 410 Gone because it was never there in the first place.
I also would like something more fitting than 404 Not Found because I would really like to give the message "Does Not Exist": not just "Not Found, what happened? Who knows?". How can I tell a User-Agent that it is a waste of both our times to ask for it again?
Based on HTTP 1.1, 404 Not Found seems like the most correct option, because the definition ends with "or when no other response is applicable" but I am not fully satisfied with that. Any other idea?
Have you considered 403 Forbidden? It sounds like what you might be looking for and you can include a message in the body of the response that tells the client that the resource will never exist.
The server understood the request, but is refusing to fulfill it.
Authorization will not help and the request SHOULD NOT be repeated. If
the request method was not HEAD and the server wishes to make public
why the request has not been fulfilled, it SHOULD describe the reason
for the refusal in the entity. If the server does not wish to make
this information available to the client, the status code 404 (Not
Found) can be used instead.

Is it acceptable to modify the text sent with the HTTP status code?

I'm implementing a 'testing mode' with my website which will forbid access to certain pages while they are undergoing construction, making them only accessible to administrators for private testing. I was planning on using the 401 status code, since the page does exist but they are not allowed to use it, and they may or may not be authenticated, yet only certain users (basically me) would still be allowed to access the page.
The thing I'm wondering is if the text after the HTTP/1.1 401 part mattered? Does it have to be Unauthorized or can it basically be whatever you want to put after it, so long as the 401 is still appropriate for the error? I wanted to send a message such as Temporarily Unavailable to indicate that the page is normally available to all visitors, but is undergoing reconstruction and is temporarily unavailable. Should I do this or not?
You may change them.
The status messages (technically called "reason phrases") are only recommendations and "MAY be changed without affecting the protocol)."
See http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1
However, you SHOULD :-) still use the codes properly and give meaningful messages. Only use a 401 if your condition is what the RFC says a 401 should be.
Yes, the reason phrase can be changed. It doesn't affect the meaning of the message.
But if you need to say "temporarily unavailable", you need to make it 5xx (server) code. 503 seems right here (see RFC 2616, Section 10.5.4).
You MAY change the text (very few http clients pay any attention to it), but it is better to use the most applicable response code. Afterall, indicating the reason for failure is how the various response codes were intended to be used.
Perhaps this fits:
404 Not Found The requested resource could not be found but may be
available again in the future.[2] Subsequent requests by the client
are permissible.

Is it bad practise to serve an error 403 page for an application-level policy?

Say I have a website that allows anyone to log in through oauth or similar, but only allows certain uses to create or modify content. Should they somehow make a request for page for creating a new post, I'll do a check and redirect them if they don't have the appropriate permissions.
It is considered acceptable to redirect to the "403 Error" page in this situation? There was no actual HTTP response with a 403 status code, there was no database- or server- level query that was failed - just my business logic. Am I misappropriating the idea of HTTP status codes if I serve an error 403 page with a specific explanatory message?
You are free to do so, but I think if you want to expose an API you would use an actual 403 response because they carry meaning that will be nicely handled by the client.
If you want to display a page to the client and will be using redirect, you will lose this meaning of the "403".
Isn't it better to just redirect them to an explanation page without including the "403" code. Or better yet, redirect them to a more helpful place, like the sign up page if that is what they have to do to make a post, or back to the original page with a floating message.
We want to help the user get closer to their goals instead of confusing them with technical error codes.
There is often a lot of discussion about this very topic and it comes down to the following choices:
a 5xx? Of course not. This is not a server error.
a 400? Not really, it wasn't a malformed request.
a 401? Probably not, 401 is generally for authorization in general, not application-level permissions. If your user has already logged in but has the wrong role, and you want to let the user know, then use something else.
a 404? Perhaps, as the server can't find the resource for this particular user, but if you want to tell the user "well such a resource is available but you can't have it because you lack permissions" then go with something else.
a 403? Actually, this one makes a lot of sense. Here is the definition from the RFC
403 Forbidden The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
In your question you mention your intention to redirect the user. If you are making a RESTFUL web service then just return the 403. If you are doing an entire web app, you can control the 403 and redirect....

Do I need to use http redirect code 302 or 307?

Suppose I have a page on my website to show media releases for the current month
http://www.mysite.com/mediareleases.aspx
And for reasons which it's mundane to go into*, this page MUST be given a query string with the current day of the month in order to produce this list:
http://www.mysite.com/mediareleases.aspx?prevDays=18
As such I need to redirect clients requesting http://www.mysite.com/mediareleases.aspx to http://www.mysite.com/mediareleases.aspx?prevDays=whateverDayOfTheMonthItIs
My question is, if I want google to index the page without the query parameter, should I use status code 302 or 307 to perform the redirect?
Both indicate that the page has "temporarily" moved - which is what I want because the page "moves" every day if you get my meaning.
[*] I'm using a feature of a closed-source .NET CMS so my hands are tied.
Google's documentation seems to indicate that both 302 and 307 are treated equivalently, and that "Googlebot will continue to crawl and index the original location."
But in the face of ambiguity, you might as well dig into the RFCs and try to do the Right Thing, with the naïve hope that the crawlers will do the same. In this case, RFC 2616 § 10.3 contains nearly identical definitions for each response code, with one exception:
302: Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests.
307: Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI for future requests.
Which does not strike me as a significant distinction. My reading is that 302 instructs clients that webmasters are untrustworthy, and 307 explicitly tells webmasters that clients will not trust them, so they may freely alter the redirect.
I think the more telling point is the note in 302's definition:
Note: RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location field-value regardless of the original request method. The status codes 303 and 307 have been added for servers that wish to make unambiguously clear which kind of reaction is expected of the client.
Which, to me, indicates that 302 and 307 are largely equivalent, but that HTTP/1.0 clients failed to implement 302 correctly the first time around.
Short answer: neither. In most cases the code you really want to use is 303.
For the long answer, first we need some background.
When getting a redirect code the client can (A) load the new location using the same request type or (B) it can overwrite it and use GET.
The HTTP 1.0 spec did not have 303 and 307, it only had 302, which mandated the (A) behavior. But in practice it was discovered that (A) led to a problem with submitted forms.
Say you have a contact form, the visitor fills it and submits it and the client gets a 302 to a page saying "thanks, we'll get back to you". The form was sent using POST so the thanks page is also loaded using POST. Now suppose the visitor hits reload; the request is resent the same way it was obtained the first time, which is with a POST (and the same payload in the body). End result: the form gets submitted twice (and once more for every reload). Even if the client asks the user for confirmation before doing that, it's still annoying in most cases.
This problem became so prevalent that client producers decided to override the spec and issue GET requests for the redirected location. Basically, it was an oversight in the HTTP 1.0 spec. What clients needed most was a 303 (and behavior (B) above), but instead they only got 302 (and (A)).
If HTTP 1.0 would have offered both 302 and 303 there would have been no problem. But it didn't, so it resulted in a 302 which nobody used correctly. So HTTP 1.1 added 303 (badly needed) but also decided to add 307, which is technically identical to 302, but is a sort of "explicit 302"; it says "yeah, I know the issues surrounding 302, I know what I'm doing, give me behavior (A)".
Now, back to our question. You see now why in most cases you will want 303.
Cases where you want to preserve the request type are very rare. And if you do find yourself such a case, the answer is simple: use 302. Either the client speaks HTTP 1.0, in which case it can't understand 307; or it speaks HTTP 1.1, which means it has no reason to preserve the rebelious behavior of old clients ie. it implements 302 correctly, so use it!
5 years on... note that the behaviour of 307 has been updated by RFC-7231#6.4.7 in June 2014, and is now significantly different from a 302, in that the method may not change:
The 307 (Temporary Redirect) status code indicates that the target
resource resides temporarily under a different URI and the user agent
MUST NOT change the request method if it performs an automatic
redirection to that URI.
Probably not an issue for the original question, but may be relevant to others who come across this question just looking for the difference.
I feel your pain. As for a solution, it's hard to say what search engines will do. It seems that each one has its own way of handling redirects. This link suggests that a 302 will index the contents of the redirected page but still use the main page link, but it's not clear what a 307 will do.
Another way you could consider proceeding is with a javascript redirect and a <noscript> tag explaining what's going on. That will also foul up non-javascript browsers, and you'd have to proceed with caution to avoid Google's sneaky-site detection routine, but I suspect that as long as your noscript contains a hyperlink that matches the new URL you'd be OK.
Either way I'd still pursue doing a purely server-side request if at all possible. Heck, if your expected traffic is light, you could treat your home page as a proxy in the case where there's no querystring. Have it use a background thread to request itself with the querystring and pipe out the results. :-)
edit just saw you're using .NET. Maybe consider this answer from SO: C# Can i modify Request.Form's variables? .

Resources