---
title: HTTP Safety Doesn't Happen by Accident
teaser: What are safe and unsafe HTTP methods, and why does it matter?
tags: web,http
author: George Brocklehurst
published_on: 2015-06-12
---

Before the days of CSS, JavaScript, AJAX, and Web 2.0, there were two main ways
for a Web user to tell their browser to make a request to a Web server:

1. Clicking on a link to a different page, and
2. clicking on a button to submit a form.

This distinction was helpful to users in the brave new world of the Web.
Clicking on a link meant that you wanted to see a document: you were requesting
information from the server, but that was all. You didn't want anything to
change. Submitting a form was different: it meant that you wanted the server to
do something special; something tailored to you, and based on the information
you'd provided. Submitting a form could run a program, or send an email, or even
leave a permanent mark on the Web.

Under the surface, these two actions were making different kinds of requests.
Clicking on a link was making a request using the <dfn>GET</dfn> method, which
gets information from a server, while submitting a form was making a request
using the <dfn>POST</dfn> method<sup><a href="#fn1" id="r1" title="Footnote
1">1</a></sup>, which sends—or posts—information to a server.

The distinction between these types of requests is important. The HTTP
specification tells us that GET is *safe*, whereas POST is *unsafe*. Here's how
[RFC 7231][rfc7231], the latest version of the HTTP 1.1
specification, defines safety:

<blockquote cite="http://tools.ietf.org/html/rfc7231#section-4.2.1" lang="en-US">
<p>Request methods are considered "safe" if their defined semantics are
   essentially read-only; i.e., the client does not request, and does
   not expect, any state change on the origin server as a result of
   applying a safe method to a target resource.  Likewise, reasonable
   use of a safe method is not expected to cause any harm, loss of
   property, or unusual burden on the origin server.</p>

<p>This definition of safe methods does not prevent an implementation
   from including behavior that is potentially harmful, that is not
   entirely read-only, or that causes side effects while invoking a safe
   method.  What is important, however, is that the client did not
   request that additional behavior and cannot be held accountable for
   it.  For example, most servers append request information to access
   log files at the completion of every response, regardless of the
   method, and that is considered safe even though the log storage might
   become full and crash the server.  Likewise, a safe request initiated
   by selecting an advertisement on the Web will often have the side
   effect of charging an advertising account.</p></blockquote>

The spec goes on to explain that this distinction is important because it
defines the kind of requests that automated programs—anything from the Google
search bot, to a browser extension, to a little Ruby script you might write on
the command line—can reasonably make without inadvertently leaving a trail of
devastation in their wake.

It also encourages people building user agents—typically browsers, but really
any software that makes Web requests on behalf of a user—to think about the user
interface associated with safe and unsafe requests:

<blockquote cite="http://tools.ietf.org/html/rfc7231#section-4.2.1" lang="en-US">
<p>A user agent SHOULD distinguish between safe and unsafe methods when
   presenting potential actions to a user, such that the user can be
   made aware of an unsafe action before it is requested.</p></blockquote>

On today's Web, things aren't so clear-cut as they were in the good old days
of the link and the button. CSS can make buttons look like links, and links look
like buttons. JavaScript can make buttons behave like links, and links behave
like buttons, and make safe and unsafe requests without anyone clicking on
anything at all.

But HTTP is still there, underpinning everything we do<sup><a href="#fn2"
id="r2" title="Footnote 2">2</a></sup>. The distinction between safe and unsafe
methods, between GET and POST, is still important. As we build the Web, we
should always remember the platform we're building on and how it works.

On the server-side, we should ensure that safe requests to our applications
really are safe. Our Rails `show` and `index` actions shouldn't write to our
databases, make unsafe requests to third-party APIs, or make other changes in
the world that our users neither wanted nor expected.

On the client-side, our complex and JavaScript-heavy applications often have
more in common with user agents than documents, and so the things the HTTP spec
requires of user agents fall to us as well. We should ensure that our users
understand what's safe and what isn't. Viewed in this light, that old Rails
idiom of `link_to @blog_post, method: :delete` doesn't seem so helpful after
all, and `button_to` would make things clearer. Suddenly, being more
conscientious about popping up a confirmation dialog before our JavaScript
triggers an unsafe request seems much more important.

The HTTP specification is full of insights that shed light on how we can build
better Web sites. If you only read one RFC this summer, make sure it's
[RFC 7231][rfc7231]<sup><a href="#fn3" id="r3" title="Footnote
3">3</a></sup>. And if you forget everything else in this post, just remember
this one thing: GET requests don't have side effects.

---

<a href="#r1" id="fn1">[1]</a> Forms can also make GET requests (e.g. search forms should GET
rather than POSTing) but a link can never make a POST request without JavaScript
getting involved.
</p>

<a href="#r2" id="fn2">[2]</a> Maybe not quite everything these days—WebSockets speak other
protocols—but definitely still the vast majority of things.

<a href="#r3" id="fn3">[3]</a> If you read more than one,
you might enjoy one of the sequels, like [RFC 7232][rfc7232];
or the prequel, [RFC 7230][rfc7230];
or maybe even the art-house original version of HTTP/1.1 from 1999,
before it was re-made in six parts with a big Hollywood budget,
[RFC 2616][rfc2616].

[rfc2616]: http://tools.ietf.org/html/rfc2616 "Hypertext Transfer Protocol -- HTTP/1.1"
[rfc7230]: http://tools.ietf.org/html/rfc7230 "Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing"
[rfc7231]: http://tools.ietf.org/html/rfc7231 "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content"
[rfc7232]: http://tools.ietf.org/html/rfc7232 "Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests"
