/
index.html
186 lines (133 loc) · 10.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Async HTTP Responses with Response Redirection :: Jeff Lindsay
</title>
<meta name="description" content="" />
<meta name="author" content="Jeff Lindsay" />
<script type="text/javascript" src="/scripts/jquery-1.7.2.min.js"></script>
<link href="http://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css" />
<link href="http://fonts.googleapis.com/css?family=VT323" rel="stylesheet" type="text/css" />
<link rel="stylesheet" type="text/css" href="/style/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="/style/pager.min.css" />
<link rel="stylesheet" type="text/css" href="/style/alerts.min.css" />
<link rel="stylesheet/less" type="text/css" href="/style/progrium.less" />
<link rel="shortcut icon" type="image/x-icon" href="/images/JeffLindsayDeluxe.png" />
<script type="text/javascript" src="/scripts/less-1.3.0.min.js"></script>
<link rel="me" href="http://www.google.com/profiles/progrium" />
</head>
<body>
<div id="header">
<div class="container">
<div id="tree"></div>
<h2><a href="/" title="Pragmatic idealist. Builder. Thought explorer."><span>Jeff Li</span>nds<span>ay</span></a></h2>
<ul>
<li><a href="/blog">Blog</a></li>
<li><a href="http://github.com/progrium">Projects</a></li>
<!--li>Blueprints</li-->
<li><a href="/about.html">About</a></li>
<li id="hire"><a href="mailto:progrium+hire@gmail.com">Hire Me</a></li>
</ul>
</div>
</div>
<div id="content">
<div class="container">
<div class="sidebar">
<div class="portrait">
<img src="/images/JeffLindsayDeluxe.png" width="150" height="150" />
</div>
<div class="button"><a href="/blog/atom.xml">Subscribe to Blog</a></div>
<h6>Related Posts</h6>
<ul>
<li><a href="/blog/2013/01/01/where-did-localtunnel-come-from">Where did Localtunnel come from?</a></li>
<li><a href="/blog/2012/12/25/localtunnel-v2-available-in-beta">Localtunnel v2 available in beta</a></li>
<li><a href="/blog/2012/12/17/http-signatures-with-content-hmac">HTTP Signatures with Content-HMAC</a></li>
<li><a href="/blog/2012/12/15/avoiding-environmental-fallacy-with-systems-thinking">Avoiding environmental fallacy with systems thinking</a></li>
<li><a href="/blog/2012/11/26/x-callback-header-an-evented-web-building-block">X-Callback Header: Evented Web Building Block</a></li>
<li><a href="/blog/2012/11/19/from-webhooks-to-the-evented-web">From Webhooks to the Evented Web</a></li>
<li><a href="/blog/2012/09/30/piping-into-and-out-of-the-cloud-with-skypipe">Piping into and out of the cloud with skypipe</a></li>
<li><a href="/blog/2012/09/07/let-me-tell-you-about-my-website">Let me tell you about my website</a></li>
<li><a href="/blog/2010/05/11/making-a-local-web-server-public-with-localtunnel">Making a local web server public with localtunnel</a></li>
<li><a href="/blog/2010/02/02/learning-from-disparity-aka-failure">Learning from expectation disparity, aka "failure"</a></li>
</ul>
</div>
<div class="article">
<div class="date">
<span class="month">Dec</span>
<span class="day">06</span><br />
<span class="year">2012</span>
</div>
<h1><a href="/blog/2012/12/06/async-http-responses-with-response-redirection">Async HTTP Responses with Response Redirection</a></h1>
<p>What if you could perform any HTTP request, but get the response back via a webhook? This is the simple goal of Response Redirection, a simple micro-protocol for telling an HTTP server to send the response to a URL. Instead of returning the response in the connection created by the request, the response is returned in HTTP callback fashion.</p>
<p>The primary use case for this is handling HTTP responses that take longer than you would prefer to keep an open connection. As we build APIs that start interacting with the real world and human processes, you could expect operations that might take hours to days to complete.</p>
<h3 id='example_of_response_redirection'>Example of Response Redirection</h3>
<p>Response Redirection is done by performing a regular HTTP request with two additions: a Pragma directive telling the server you want the response to be redirected, and a Callback to be used for the response.</p>
<pre><code>GET /helloworld HTTP/1.1
Host: example.com
Pragma: redirect
Callback: <http://server.com/callback>; method="post"; rel="redirect"</code></pre>
<p>The response to this is a 202 Accepted or an appropriate error code. 202 Accpted is the standard response to give for operations that have been accepted and will be processed or finished later. As soon as the server as processed the request and has rendered a response, it would perform a request:</p>
<pre><code>POST /callback HTTP/1.1
Host: server.com
Status: 200 OK
Content-Length: 11
Content-Type: text/plain
Hello world</code></pre>
<p>As we talked about with the <a href='http://progrium.com/blog/2012/11/26/x-callback-header-an-evented-web-building-block/'>Callback header</a>, if a <code>secret</code> parameter was given, it would imply that an HMAC signature be provided in the callback request. We’ll revisit this again in another post.</p>
<p>If the server doesn’t understand <code>Pragma: redirect</code>, it would return a normal response to the initial request and the client would have to handle it as usual.</p>
<h3 id='using_pragma'>Using Pragma</h3>
<p>You’ll notice we didn’t invent a header to tell the server to we want to do Response Redirection. You may remember Pragma’s original use was only for <code>Pragma: no-cache</code> and was eventually replaced with other cache control headers. However, the semantics of Pragma remain useful. To quote the <a href='http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.32'>HTTP 1.1 spec</a>:</p>
<blockquote>
<p>The Pragma general-header field is used to include implementation-specific directives that might apply to any recipient along the request/response chain.</p>
</blockquote>
<p>Another potential header field would be the <a href='http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.20'>Expect header</a>. The Expect header is designed to let the client specify certain behaviors expected of the server. This would be perfect except for this property:</p>
<blockquote>
<p>The Expect mechanism is hop-by-hop: that is, an HTTP/1.1 proxy MUST return a 417 (Expectation Failed) status if it receives a request with an expectation that it cannot meet.</p>
</blockquote>
<p>In today’s world, this renders it useless unless we were talking about changing the behavior of proxies. The Pragma header was designed to be forwarded by proxies and ignored if it doesn’t know how to fulfill the directive.</p>
<h3 id='alternate_implementation'>Alternate Implementation</h3>
<p>In the discussion that followed the Callback header post, not only did we learn that the <code>X-</code> header prefix <a href='http://tools.ietf.org/html/rfc6648'>is now deprecated</a>, but there is an RFC draft called <a href='http://tools.ietf.org/html/draft-snell-http-prefer-17'>Prefer Header for HTTP</a>.</p>
<p>It actually addresses the issue with the Expect header, providing an alternative for specifying optional preferences for how the server handles a request. One of the example preferences is for returning the response asynchronously, which is exactly what we’re achieving with Response Redirection. The only missing element is the callback, which we can easily include with our Callback header. Here we augment an example directly from the spec:</p>
<pre><code>POST /collection HTTP/1.1
Host: example.org
Content-Type: text/plain
Prefer: respond-async
Callback: <http://server.com/callback>; rel="respond-async"
{Data}</code></pre>
<p>The server would respond with 202 Accepted, just as we would have had with the Pragma implementation. It’s up for discussion which implementation is ideal.</p>
<h3 id='last_thoughts'>Last Thoughts</h3>
<p>Granted, there are likely better ways to approach the use case we described at the beginning. Creating a resource immediately and subscribing to state changes might actually be ideal. Perhaps the Response Redirection spec is purely academic. That brings us again to the idea of HTTP Subscriptions, which I’ll get to posting about soon.</p>
<p>However, Response Redirection is a great example of a simple protocol built on top of the Callback header. The use of Prefer and Pragma will also set the stage for the design decisions of my initial informal draft of HTTP Subscriptions. It will continue this trend of reusing existing pieces of technology (Pragma, Expect, Prefer, Callback) as building blocks that, from my perspective, were intended to be re-combined to achieve new behavior.</p>
<p>Let me know what you think in the comments or in the <a href='https://groups.google.com/forum/#!forum/webhooks'>Webhooks Google Group</a>.</p>
</div>
<hr />
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'progrium'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
</div>
<div id="roots">
<img src="/images/roots.png" />
</div>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-6824126-1");
pageTracker._trackPageview();
} catch(err) {}</script>
</body>
</html>