Currently browsing http


HTTP Status: Redirection

Sun, 20 Jul 2008 22:58 UTC

I’ve been rather uninspired and, therefore, uninterested in blogging lately, which is why I’ve neglected to continue my series on HTTP status codes. However, while trying to figure out a quick and easy way to delete tons of received direct messages from my Twitter account, I stumbled across one of my HTTP pet peeves coupled with the odd use of a 3xx status code, which inspired me to launch into a short rant followed by a discussion on the redirection series of status codes.

First, the pet peeve: I cannot stand it when someone uses a GET request to modify information. I don’t care how secure it is because you’re checking my session and login details, sending a GET request to /direct_messages/destroy/30264861 should not do anything other that retrieve the resource located there. If using GET, the user agent thinks it’s a safe action and will not know that it should warn me that the action I’m about to take could modify information. CSRF anyone?

Come on, people! GET is a safe method. Client-side developers (among others) would do well to learn this.

Consequently, there is no resource at that location, and that also peeves me. Instead, I get a weird 302 Moved Temporarily HTTP redirect that also includes a Status: 302 Found header. WTF? Come on! It’s 2008. RFC 2616 has been out for nine years now. Is there anyone using Twitter on a user agent old enough that it only works for HTTP 1.0? (I’ll wager that I’ll get responses from people about how some mobile browsers only understand HTTP 1.0.)

This leads me to the second thing I want to discuss: HTTP redirections.

Historically (in HTTP 1.0), HTTP had two status codes for redirection: 301 Moved Permanently and 302 Moved Temporarily. However, 302 became misused and abused by user agents that didn’t follow the spec, which stated: “If the 302 status code is received in response to a request using the POST method, the user agent must not automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.” Instead, user agents would often simply use a GET request on the value of the Location header, redirecting the user without warning.

Take a moment now to think about this. Why would the user agent send a GET request for the value of the Location header without asking the user if it’s okay? Because the user agent thinks it’s safe to do so. Remember my earlier rant?

Nevertheless, the user agents weren’t supposed to be behaving this way, but developers used 302 Moved Temporarily as the common method for redirecting after POST actions, and following the spec would make for a cumbersome user experience, especially if I had to approve every single redirect that occurs after I POST something. (This actually happens on mobile browsers quite frequently, since the mobile browser—on my phone, at least (a RAZR)—properly implements the expected behavior, thus making a crappy experience for me.)

So, to rectify the situation, HTTP 1.1 introduced 303 See Other and then later 307 Temporary Redirect (changing the meaning of 302 to Found).

The 303 See Other status code unambiguously states that the value of the Location header “SHOULD be retrieved using a GET method” and that the “new URI is not a substitute reference for the originally requested resource.” That is, if the user agent originally used POST to send data, then the server can tell the user agent to safely redirect to another resource using GET, and the new resource should not be expected to act on the data sent in the original POST request.

Likewise, the 307 Temporary Redirect status code unambiguously states that if it is “received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.” So, if I POST a form to a server that sends back a 307 Temporary Redirect, then the user agent should ask me whether I want to proceed. If I say “yes,” then the user agent will proceed to POST the data to the URI identified by the Location header.

So, a couple rules of thumb: 302 Found is still the de-facto redirection method, though it may not mean what you want it to mean or behave properly on all user agents. If you want to process a POST request and then safely redirect the user agent using GET, use 303 See Other. If you want to redirect a POST request (that is, send the posted data to a different location), use 307 Temporary Redirect. If the original request was GET or HEAD, and you simply want to redirect the user agent, then either 302 Found or 307 Temporary Redirect are proper, though I prefer the 307.

To explicitly tell user agents (and particularly search engines and proxies) that something has moved permanently and that they should update their links, use 301 Moved Permanently .

Comments 2 Comments »  Permalink Permalink  Tags Tags: , , ,


HTTP Status: 204 No Content and 205 Reset Content

Wed, 7 May 2008 2:08 UTC

The 200 range of HTTP status codes represents successful requests. I’ve already covered 201 Created and 202 Accepted and 206 Partial Content. Today, I’ll wrap up my discussion of the 200 range by talking about 204 No Content and 205 Reset Content. The 200 OK response is probably the status with which most are familiar, and I’ll discuss it later when covering the HTTP verbs.

The 204 No Content response is useful in a web service when you want to return a success message but do not want to return a message in the body or do not have a body to return. In my personal experience, I use this when DELETE requests are sent to an Atom web service. If the resource is successfully deleted, the service returns a 204 No Content status message. This tells the client that the deletion was successful, and that’s really all the client needs to know. There’s nothing to return because it was deleted.

However, even outside of the web services realm, the 204 No Content status actually means something to a user agent (browser). The HTTP specification (RFC 2616) states the following about the 204 No Content status code:

If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent’s active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent’s active view.

This means that, if I have an HTML form and submit it, then, if the server returns a 204 status code, the browser should not refresh the form or take me to another page. The document view does not change, and I remain at the form. All of the data I entered remains unchanged. All browsers I tested support this, but, in practice, it is not very useful since there’s no indication to a user that anything happened on the server side.

However, consider the use of 204 No Content in an Ajax application. If the Ajax library used simply looks for a success message of 204 in response to the requests it sends, then it can present a success message to the user without changing any of the UI elements, as this response intends. This is also useful because the service doesn’t need to send back any data; it needs only tell the client that the request was successful.

On the other hand, with a 205 Reset Content response, the intent is to tell the client to clear the content from the form or to refresh the UI. That is, I could fill out a form, click the submit button, and the form I am currently working on would refresh to its default values if the client receives a 205 response. According to the HTTP spec, a 205 response means:

The server has fulfilled the request and the user agent SHOULD reset the document view which caused the request to be sent. This response is primarily intended to allow input for actions to take place via user input, followed by a clearing of the form in which the input is given so that the user can easily initiate another input action.

The problem is that I have not found a browser yet that supports this behavior. Browsers either treat a 205 like it’s a 204, or they simply treat it as a 200. This does not mean, though, that Ajax applications cannot properly respect a 205 response. In an Ajax application, if the client receives a 205 response (instead of a 204 response), then the UI elements should change back to their default state.

In RESTful Web Services, Richardson and Ruby make this distinction between 204 and 204:

In data entry terms: 204 is good for making a series of edits to a single record; 205 is good for entering a series of records in succession.

In my simple browser test to see what browsers supported 204 and 205 on forms (without using any Ajax), here’s what I found:

Firefox 2.0.0.14
  - 204 - supported
  - 205 - treated like 204

Safari 3.1.1
  - 204 - supported
  - 205 - treated like 200

Opera 9.27
  - 204 - supported
  - 205 - treated like 200

Internet Explorer 7 (7.0.5730.13)
  - 204 - supported
  - 205 - treated like 200

Internet Explorer 8 beta 1 (8.0.6001.17184)
  - 204 - supported
  - 205 - treated like 200

Firefox 3 beta 5
  - 204 - supported
  - 205 - treated like 204

Since I know I’ll be asked this question, to send back a 204 or 205 response with PHP, see the PHP manual on the use of the header() function. :-)

Comments 3 Comments »  Permalink Permalink  Tags Tags: , , ,


HTTP Status: 206 Partial Content and Range Requests

Mon, 5 May 2008 2:17 UTC

Akki commented on my 100 Continue post, asking:

I was wondering if there was a response status to allow a large file to be “served” in parts and in just one response?

While I’ve never done this myself, I did some research to see how it might be done, and I’ve come up with a solution that I wish I could call clever, innovative, and many other words that make me sound like I came up with a smart solution, but the reality of it is that HTTP was made to support this behavior, so I’ll just tell you how to do it with standard HTTP.

First of all, let’s create a scenario. Say I want to request a very large file from a service, but before I do so, I want to find out exactly how large it is and whether the service supports “range requests.” To do this, I make a HEAD request to the large resource I want to retrieve. The HEAD method is a standard HTTP method that acts as if I’ve made a GET request, but it returns only the headers and not the body. This allows me to find out some information about the resource without actually taking the time or using the bandwidth to download it. For example, I can read the Content-Length header and determine the size of the resource.

Another header of great importance is the Accept-Ranges header. If it’s present, it may contain a value of “bytes.” If so, I know that I can make a GET request and request a byte range to retrieve only those bytes. This is the first important key component:

If you are building a service that accepts byte range requests, let clients know by providing the Accept-Ranges header in response to GET and HEAD requests.

So, now, I know I can make a range request to the service, which I do by sending a standard GET request including a Range header that specifies the range of bytes I’m requesting, like so: Range: bytes=0-999. The service should then respond with with a 206 Partial Content status code, a Content-Range header, and the requested range of bytes. This is the second key component:

If a client makes a request of your service with a Range header, return a 206 Partial Content response containing a Content-Range header and the requested range of bytes for the resource in the body. The Content-Length value should be the length of what is actually returned and not the full length of the resource.

From then on, it’s a matter of the client continuing to make requests until it has retrieved all of the bytes it wishes to get from the resource. If the client makes a range request that is out of bounds—that is, none of the range values overlap the extent of the resource—the service should respond with a 416 Requested Range Not Satisfiable status.

I should note that the service cannot force the client to make a range request. It is entirely up to the client to make such requests, so the service should honor all standard GET requests that do not contain a Range header by sending back the full representation of the requested resource. If your service allows range requests, it is to your benefit to tell the client with an Accept-Ranges header. If you want to explicitly tell the client that you do not allow range requests, send a value of “none” back with the Accept-Ranges header.

Since I learn best by looking at real-life examples, I’ll provide one for you. Here’s a real example making range requests with Flickr. I’ve removed some of the headers for simplicity and clarity.

HEAD /2390/2253727548_a413c88ab3_s.jpg HTTP/1.1
Host: farm3.static.flickr.com

HTTP/1.0 200 OK
Date: Mon, 05 May 2008 00:33:14 GMT
Server: Apache/2.0.52 (Red Hat)
Accept-Ranges: bytes
Content-Length: 3980
Content-Type: image/jpeg

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GET /2390/2253727548_a413c88ab3_s.jpg HTTP/1.1
Host: farm3.static.flickr.com
Range: bytes=0-999

HTTP/1.0 206 Partial Content
Date: Mon, 05 May 2008 00:36:57 GMT
Server: Apache/2.0.52 (Red Hat)
Accept-Ranges: bytes
Content-Length: 1000
Content-Range: bytes 0-999/3980
Content-Type: image/jpeg

{binary data}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GET /2390/2253727548_a413c88ab3_s.jpg HTTP/1.1
Host: farm3.static.flickr.com
Range: bytes=1000-

HTTP/1.0 206 Partial Content
Date: Mon, 05 May 2008 00:37:54 GMT
Server: Apache/2.0.52 (Red Hat)
Accept-Ranges: bytes
Content-Length: 2980
Content-Range: bytes 1000-3979/3980
Content-Type: image/jpeg

{binary data}

Comments 3 Comments »  Permalink Permalink  Tags Tags: , , ,


HTTP Status: 201 Created vs. 202 Accepted

Fri, 25 Apr 2008 18:48 UTC

Continuing my series on HTTP status codes, I’d like to talk today about the use of the 201 Created and 202 Accepted codes.

I should make a point of clarification first, though. When I’m discussing the use of status codes, I have in mind Web services applications with perhaps rich clients that interface with them and not necessarily standard, browser-based Web apps. Browsers should be able to handle these status codes, but they are not necessarily the richest clients to use as an interface to your Web service, so they may not be able to handle the responses as intended.

Moving along…

Recently, while designing an application that uses the Atom Publishing Protocol, I found myself using the 201 Created status code as a response to successful POST requests for creation of new content in the service. In the body of the response, I would return a full representation of the newly created resource, and I would include a Location header with a URI that points to the location of the newly created resource. (Instead of returning a full representation of the created resource, you may return a list of URIs pointing to locations for the resource(s) created.)

In general, this is a good practice, though most of us find ourselves returning the standard 200 OK code. (Using 200 OK is still acceptable, though I’ll have more to say on that in a future post.) However, I ran into a problem when I realized that the resource itself does not yet exist, nor might it ever exist; it all depends on our business rules, which require various processes to occur before we “publish” the content. So, the 201 Created response is misleading to the client because nothing has been created yet, and the representation of the resource is inaccurate since the resource does not yet exist. The resource is really in a pending state.

Enter the 202 Accepted status code.

I decided to use the 202 Accepted status code as the more proper response to these types of requests. 202 Accepted means that the service successfully accepted the request and there are, as of yet, no problems with it (i.e. no immediate data validation problems), but it can’t create the resource until it does further processing. This response does not promise that the resource will be created, though. So, it’s perfect for pending requests, since a pending request could be rejected while it’s being processed.

The HTTP spec says that a 202 Accepted response SHOULD include an indication of the request’s current status. To this end, for our service, I have it return an Atom Entry Document with content that describes what’s going on, i.e. the request succeeded but requires further processing before it can be published. It may also be beneficial to clients to include a Location header with a URI that can be used later to check on the status of the request.

When the client checks the status URI later, if the item is still pending then the status URI might return a 200 OK response with an entity body describing this. If the resource has been created, then perhaps the status URI would return a 201 Created response with a Location header pointing to the location of the new resource. If the item was not created for some reason, then perhaps the status URI would return a 410 Gone response. In this case, you should include an entity body explaining why the resource is gone, i.e. “We were unable to create this resource due to processing errors.” A 404 Not Found response would also be acceptable, but the 410 Gone response implies permanence; the requested resource is gone for good.

The status URI described here is a temporary URI used only for checking on the status of the request. It would eventually be unavailable after the resource has been created or rejected, but the time frame for this is up to you.

Comments 3 Comments »  Permalink Permalink  Tags Tags: , , ,


HTTP Status: 100 Continue

Tue, 22 Apr 2008 20:26 UTC

As a self-described HTTP status code pedant and an architect of RESTful Web services, I’ve spent a great deal of time researching and thinking about the proper use of HTTP status codes in Web applications. It occurs to me that many people use status codes in their applications in ways that I find improper, so I’ve decided to start up a series of blog posts to talk about select status codes and how they might appropriately fit within your Web applications, specifically in a RESTful manner. Consider these “Ben’s HTTP Status Codes Best Practices.”

I won’t be covering these status codes in any particular order. However, the first code up is 100 Continue merely because I’ve been thinking about it lately.

The 100 Continue status code is an informational response that tells the client application it can continue sending the request. In short, the client can make an abbreviated request of the service to check whether or not it should continue making the full request. The service can then respond either “yes” (100 Continue) or “no” (417 Expectation Failed) with an explanation of why not. In RESTful Web Services, Richardson and Ruby refer to this as a “look-before-you-leap” (LBYL) request.

This is helpful in situations where the client might want to post or put a very large file to the service but wants to ensure that the service will accept it before actually sending the file. Consider the following request:

POST /content/videos HTTP/1.1
Host: media.example.org
Content-Type: video/mp4
Content-Length: 105910000
Authorization: Basic bWFkZTp5b3VfbG9vaw==
Expect: 100-continue

In this case, the client is attempting to post an MPEG-4 video that is 101MB. The client sends this request to your service without the video in the body, and it includes the Expect: 100-continue header. Let’s say your service limits uploads to 100MB. In that case, you would return a 417 Expectation Failed including a reason for the failure in the body of the response.

By now, you can probably see how this can be extended to apply to any of the other headers. For example, a client can try a POST or a PUT request first just to see if its authorization succeeds. If it does, your service would return 100, letting the client know it may proceed with the request. Likewise, the client might want to determine whether the service will accept a video/mp4 file before sending it. The list goes on.

It should be noted that the service shouldn’t require the client to use a LBYL request, but it can be helpful to a client so that it doesn’t attempt to send something that would fail at the service anyway.

I’m considering implementing these kinds of responses in a service I’m building, so I’ll let you know how it goes. :-)

Comments 6 Comments »  Permalink Permalink  Tags Tags: , , ,


Supporting PUT & DELETE in the Zend Framework

Wed, 27 Feb 2008 18:51 UTC

Creating a RESTful Web service is not simply about serving read-only content through HTTP GET requests. It’s about using the full range of HTTP’s constrained interface to allow clients to consume or create resources within your service. Take a look at CouchDB, for example. Its initial releases look very promising, and the server accepts GET, POST, PUT, and DELETE requests to manipulate resources in the system. I can’t wait until the project implements authentication and authorization features; then, it will look much more attractive for real-world use.

But I digress…

I’ve never been too happy with the Zend Framework’s RPC-based approach to creating RESTful Web services with Zend_Rest_Server, even though I have seen some good discussion about using routes and Zend_Rest_Server to create a resource-oriented architecture. Rather than get too in-depth about this issue, I’ll just point to this thread and save my full thoughts on Zend_Rest_Server for another day.

Suffice it to say, Zend_Rest_Server is not focused on resources but, instead, what you can do with those resources (procedures, methods, verbs) and also assumes you’re only ever going to provide an XML-based, read-only REST service. With REST, this is not the case, and, with the publication of the Atom Publishing Protocol (a protocol that follows the REST architectural style) as RFC 5023, now is the time more than ever to grasp the read-write capabilities of the RESTful Web.

But I digress (again)...

I’ve recently been wrapped up in an effort to design and implement a RESTful API using the Atom Protocol for a project at work. We are using the Zend Framework as the underlying framework for the project, so, in order to follow the Atom Protocol, I needed to support the HTTP methods PUT and DELETE. Apache can handle GET and POST easily because the request itself tells Apache the resource to use when processing the request. With PUT or DELETE, the resource identified by the request may not even exist, so Apache needs you to specify a script to process the request. To do this, I added the following lines to my virtual host configuration:

# PUT and DELETE support
Script PUT /index.php
Script DELETE /index.php

Now, all PUT and DELETE requests are handled by the Zend Framework bootstrap script and the dispatcher handles them in the same way it handles GET and POST requests.

To further support other HTTP methods and the REST architectural style, I’ve proposed the addition of the following methods on the Zend_Controller_Request_Http class:

  • isGet() – Was the request made by GET?
  • isPut() – Was the request made by PUT?
  • isDelete() – Was the request made by DELETE?
  • isHead() – Was the request made by HEAD?
  • isOptions() – Was the request made by OPTIONS?

Error Response Body For Atom

Thu, 21 Feb 2008 2:44 UTC

I’ve spent the last month deeply entrenched in the intricacies and idiosyncrasies of RFC 5023 and RFC 4287. You could say that we’re pretty intimate right now… but we haven’t yet made it to “third base.” I’m a gentleman, mind you!

I am, of course, talking about the RFCs for the Atom Publishing Protocol and Atom Syndication Format, and, during my study and research as I’ve been designing and architecting a RESTful API based on AtomPub, I’ve found that, while the AtomPub suggests and describes HTTP status codes to use in return for various behaviors, it does not, in fact, define the format of the response entity. The AtomPub even goes so far as to state in Section 5.5:

Implementers are asked to note that according to the HTTP specification, HTTP 4xx and 5xx response entities SHOULD include a human-readable explanation of the error.

Still, it doesn’t describe the format of that “human-readable explanation.”

This led me to do quite a bit of searching, which turned up some old posts on the atom-syntax mailing list that addressed questions about error responses:

On August 2, 2003, Joe Gregorio wrote in response to someone’s question about error repsponses:

You are right that the specification at this time does not cover error 
codes. In general the HTTP Status code should be the first line of 
defense, such as 403 Not Authorized, etc. There are errors that will 
need more detail than just the status code, and I see three possibilities:

1. Do nothing. That is, let the server decide the error code and 
formatting to return it in. For example, when you get a 404 on a 
web-site you often get an HTML page or a text/plain document. Not my 
favorite option.

2. Mandate a text/plain result that describes the problem.

3. The third option is to define an XML format for describing errors, e.g.

<error>
   <title></title>
   <description></description>
</error>

A few days later (August 8th), Joe asked the question, “How should errors be handled?” Sam Ruby replied:

Why reinvent?

http://www.w3.org/TR/SOAP/#_Toc478383507

I am often (rightfully) accused of being too obtuse. So let me be 
explicit in what I am suggesting here. Design a pure REST API. 
Where there seems to be places where "some invention is required", 
see if one can reuse precisely those elements - and only those 
elements - from SOAP. What you will end up with is a fully REST 
compliant interface which will enjoy wide tooling support.

My first reaction was, “Well, why the hell would I want to use SOAP? I’m trying to be RESTful here!” However, I don’t think what Sam meant was to follow SOAP verbatim but to, rather, borrow from SOAP in much the same way that the Atom community borrowed the WSSE username token from the OASIS Web Services Security committee and adapted it from a specification for SOAP services to a more RESTful application by passing the data through HTTP headers.

Essentially, the implication was to adapt a SOAP Fault to work in a RESTful way.

Diverging from the Atom format and adapting a SOAP format to fit my needs didn’t sit well with me, unfortunately. Rather, as I thought more and more about it, I realized that the Atom format itself suited my needs just fine. So, I decided to use an Atom Entry document that would list an atom:category element for every error that occurred while attempting to process the request (i.e. data validation errors, etc.) and send this back to the user with XHTML in the atom:content element that a client could use to parse and present a human-readable message to their users.

Ultimately, I was happy, could “rest” easy, and the end result looked a bit something like this. This example represents a potential XML entity body of a 400 Bad Request response resulting from invalid data submitted to the Atom service through POST or PUT.

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>An error has occurred</title>
  <id>tag:example.org,2008-02:1.0/errors</id>
  <updated>2008-02-20T17:08:33Z</updated>
  <author>
    <name>Ben Ramsey</name>
  </author>
  <category term="9311" label="Title field missing" scheme="https://api.example.org/1.0/categories/errors"/>
  <category term="9301" label="Author field missing" scheme="https://api.example.org/1.0/categories/errors"/>
  <content type="xhtml">
    <div xmlns="http://www.w3.org/1999/xhtml">
      <p>Please correct the following errors:</p>
      <ul>
        <li>
          <a href="http://developer.example.org/errors/9311">
            Title field missing
          </a>
        </li>
        <li>
          <a href="http://developer.example.org/errors/9301">
            Author field missing
          </a>
        </li>
      </ul>
    </div>
  </content>
</entry>

Comments 2 Comments »  Permalink Permalink  Tags Tags: , , , , , , ,


HTTP Response Code Musings

Fri, 15 Jun 2007 18:18 UTC

I’ve been catching up on reading old blog posts (and, by old, I mean older than 6 months)—I’ve sort of been out of the loop lately—and I came across a November 2006 post by Adam Trachtenberg questioning the proper use of HTTP response codes in a Web Service. In particular, he was wondering when it is acceptable to return certain response codes.

I find this particularly interesting (“yes, I am serious”) since I’ve been pondering HTTP response codes and request methods a lot in light of my recent focus on RESTful applications. Adam’s question is closely in line with what I’ve been considering in a recent application (that’s not particularly RESTful).

For example, in this application, a user can set a particular item of content as “private.” That is, only the user has access to view the content on the page. Originally, when unauthorized users viewed the page, they received a 404 Not Found response. However, I didn’t feel this was the correct response to send, since the resource is clearly available on the server, and RFC 2616 states that 404 means ”[t]he server has not found anything matching the Request-URI.” In addition, we were actually specifying the reason they could not see the page in the response body, and, again, the RFC states that 404 should be used “when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.” Thus, I opted to use the 403 Forbidden response instead because ”[t]he server understood the request, but is refusing to fulfill it” and we are describing “the reason for the refusal in the entity.” Another option is to use an actual 200 OK response and deliver another entity rather than the requested resource. I imagine this is what most applications do. However, I felt that 200 OK signifies to the client that it is actually getting back the requested resource. Since that’s not happening, I wanted the client to know that it wasn’t getting the resource.

Furthermore, we’re using a McAfee HTTP API to do some virus scanning of documents. The API returns a 200 OK response when the document has finished scanning and is free from viruses, but it returns a 406 Not Acceptable response if it encounters a virus. While it doesn’t really matter to me what response code McAfee returns for a failure—what’s important is that they’ve defined what a failed response looks like and I can capture it and take appropriate action—it is interesting to note that the 4xx error codes are not intended to report responses like this. “The 4xx class of status code is intended for cases in which the client seems to have erred.” Clearly, the client did not err in this case; there was no Accept header present for which the resource could not generate a response. Instead, the POSTed file was successfully processed, and while the request was successful, McAfee found a virus and needs to report it to a client. They chose to use 406 to make this clear. Instead, I think they should use 200 OK because the POST request was successful, and the response body should indicate the status of the document (clean or infected).

So, going back to Adam’s post, he questions when to use 4xx responses and when to use 5xx. In general, if the client errs, use 4xx. If the error occurs on the server, use 5xx. However, I would recommend against using these response codes if the server can successfully fulfill the request. HTTP error codes have semantic meaning for clients, and if you apply your own meaning to them, then the client can’t respond appropriately. For example, if you use 400 Bad Request to tell the user that they provided the wrong data and you can’t process the request, then the client assumes that the server it telling it that it sent headers with malformed syntax.

The problem is that developers are attempting to apply HTTP response codes to applications that shouldn’t use HTTP response codes for communication. HTTP response codes are intended for use by HTTP servers communicating with HTTP clients. While we’re using HTTP for transfer of data in our applications, we probably shouldn’t be using the response codes provided in RFC 2616 for anything other than what they are intended since improper use of them might cause some clients to take improper action.

That said, Adam mentions the book RESTful Web Services by Leonard Richardson and Sam Ruby (published just last month). This book includes an appendix explaining when to use each status code. I’ve just ordered it and should receive it in another day or two, so expect another post from me soon continuing my rambling musings on HTTP response codes.

Comments 3 Comments »  Permalink Permalink  Tags Tags: ,