forked from webmachine/webmachine
-
Notifications
You must be signed in to change notification settings - Fork 27
/
streambody.html
176 lines (136 loc) · 5.2 KB
/
streambody.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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="author" content="Basho Technologies" />
<meta name="description" content="Webmachine streamed bodies" />
<meta name="keywords" content="webmachine http rest web" />
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="css/style-1c.css" type="text/css" />
<title>Webmachine streamed bodies</title>
</head>
<body>
<div id="content">
<h1><span class="hr"></span><a href="/">webmachine</a></h1>
<ul id="top">
<li><a href="/">Home</a></li>
<li><a href="http://bitbucket.org/justin/webmachine/">Source Code</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
<div id="left">
<h3>Webmachine streamed bodies</h3>
<p>
Webmachine allows the resource developer to handle request and
response bodies as either whole units (binary or iolist) to be handed
around at once, or else to choose to "stream" the body.
</p>
<p>
The body-handling functions are:
</p>
<ul><li><code> wrq:req_body/1 </code>
</li><li><code> wrq:stream_req_body/2 </code>
</li><li><code> wrq:set_resp_body/2 </code>
</li></ul>
<p>
The last of these, <code>wrq:set_resp_body/2</code>, is also called
implicitly with the return value of any content-producing function
such as <code>to_html/2</code>.
</p>
<p>
The first of these (<code>req_body</code>) is the simplest. It will
provide the whole incoming request body as a binary. (Unless the body
is too large, as set by <code>wrq:set_max_recv_body/2</code> or
defaulting to 50M) For the majority of resources, this is the easiest
way to handle the incoming request body.
</p>
<p>
If a resource wants to handle the incoming request body a hunk at a
time, it may call <code>wrq:stream_req_body/2</code> instead. Instead
of a binary, this produces a <code>StreamBody</code> structure.
</p>
<p>
(It is an error to call both <code>wrq:req_body/1</code> and
<code>wrq:stream_req_body/2</code> in the execution of a single
resource.)
</p>
<p>
A <code>StreamBody</code> is a pair of the form
<code>{Data,Next}</code> where <code>Data</code> is a binary and
<code>Next</code> is either the atom <code>done</code> signifying the
end of the body or else a 0-arity function that, when called, will
produce the "next" <code>StreamBody</code> structure.
</p>
<p>
The integer parameter to <code>wrq:stream_req_body/2</code> indicates
the maximum size in bytes of any <code>Hunk</code> from the resulting
<code>StreamBody</code>.
</p>
<p>
When a resource provides a body to be sent in the response, it should
use <code>wrq:set_resp_body/2</code>. The parameter to this function
may be either an iolist, representing the entire body, or else a pair
of the form <code>{stream, StreamBody}</code>.
</p>
<p>
An example may make the usage of this API clearer. A complete and
working resource module using this API in both directions:
</p>
<p>
<pre>
-module(mywebdemo_resource).
-export([init/1, allowed_methods/2, process_post/2]).
-include_lib("webmachine/include/webmachine.hrl").
init([]) -> {ok, undefined}.
allowed_methods(ReqData, State) -> {['POST'], ReqData, State}.
process_post(ReqData, State) ->
Body = get_streamed_body(wrq:stream_req_body(ReqData, 3), []),
{true, wrq:set_resp_body({stream, send_streamed_body(Body,4)},ReqData), State}.
send_streamed_body(Body, Max) ->
HunkLen=8*Max,
case Body of
<<A:HunkLen,Rest/binary>> ->
io:format("SENT ~p~n",[<<A:HunkLen>>]),
{<<A:HunkLen>>, fun() -> send_streamed_body(Rest,Max) end};
_ ->
io:format("SENT ~p~n",[Body]),
{Body, done}
end.
get_streamed_body({Hunk,done},Acc) ->
io:format("RECEIVED ~p~n",[Hunk]),
iolist_to_binary(lists:reverse([Hunk|Acc]));
get_streamed_body({Hunk,Next},Acc) ->
io:format("RECEIVED ~p~n",[Hunk]),
get_streamed_body(Next(),[Hunk|Acc]).
</pre>
</p>
<p>
If you use this resource in place of the file
<code>/tmp/mywebdemo/src/mywebdemo_resource.erl</code> in the
<a href="quickstart.html">quickstart</a> setup, you should then be able
to issue <code>curl -d '1234567890' http://127.0.0.1:8000/</code> on
the command line and the <code>io:format</code> calls will show you
what is going on.
</p>
<p>
Obviously, a realistic resource wouldn't use this API just to collect
the whole binary into memory or break one up that is already present
-- you'd use <code>req_body</code> and put a simple iolist into
<code>set_resp_body</code> instead. Also, the choices of 3 and 4
bytes as hunk size are far from optimal for most reasonable uses.
This resource is intended only as a demonstration of the API, not as a
real-world use of streaming request/response bodies.
</p>
</div>
<div id="footer">
</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-4979965-5");
pageTracker._trackPageview();
} catch(err) {}</script>
</body>
</html>