Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 259 lines (194 sloc) 10.363 kb
a231731 @benoitc add edown doc
authored
1
2
3 #hackney - simple HTTP client in Erlang#
4
5
6 Copyright (c) 2012 Benoît Chesneau.
7
64329fb @benoitc bump to 0.40
authored
8 __Version:__ 0.4
a231731 @benoitc add edown doc
authored
9
10 # hackney
11
12 **hackney** is a simple HTTP client.
13
14 Main features:
15
16 - no message passing: response is directly streamed to the current
17 process and a state is kept in a `#client{}` record.
b0fc869 @benoitc improve the readme so people can start to use it.
authored
18 - binary streams
19 - SSL support
a231731 @benoitc add edown doc
authored
20 - Keepalive handling
21 - basic authentication
27905da @benoitc ease the use in the console and improve doc
authored
22 - stream the response
a231731 @benoitc add edown doc
authored
23 - Can send files using the sendfile API
24 - Chunked encoding support
b0fc869 @benoitc improve the readme so people can start to use it.
authored
25 - Optionnal socket pool
26 - Used parse transform for shorcut methods calls:`hackney:get("https://friendpaste.com")`
a231731 @benoitc add edown doc
authored
27
bf2fcac @benoitc regen doc
authored
28 Note: This is a work in progress, see the
a231731 @benoitc add edown doc
authored
29 [TODO](http://github.com/benoitc/hackney/blob/master/TODO.md) for more
30 informations on what still need to be done.
31
b0fc869 @benoitc improve the readme so people can start to use it.
authored
32 ## Installation
33
34 Download the sources from our [Github
35 repository](http://github.com/benoitc/hackney)
36
37 To buildd the application simply run 'make'. This should build .beam, .app
38 files and documentation.
39
40 To run tests run 'make test'.
41 To generate doc, run 'make doc'.
42
43 Or add it to your rebar config<pre>{deps, [
44 ....
45 {hackney, ".*", {git, "git://github.com/benoitc/hackney.git", {branch, "master"}}}
46 ]}.</pre>
47
48 ## Basic usage
49
50 The basic usage of hackney is:
51
52 ### Start hackney
53
54 hackney is an
55 [OTP](http://www.erlang.org/doc/design_principles/users_guide.html)
56 application. You have to start it first before using all the functions.
57 The hackney applications will start for you the default socket pool.
58
59 To start in the console run :<pre>$ erl -pa ebin
60 1>> hackney:start().
61 ok</pre>
62
63 It will start hackney and all the application it depends:<pre>application:start(crypto),
64 application:start(public_key),
65 application:start(ssl),
66 application:start(hackney).</pre>
67
c7600e1 @benoitc fix typos
authored
68 Or add hackney to the applications member of your relase an app
b0fc869 @benoitc improve the readme so people can start to use it.
authored
69
c7600e1 @benoitc fix typos
authored
70 ### Simple request without pool
71
72 Do a simple a requet that will return a client state:<pre>Method = get,
b0fc869 @benoitc improve the readme so people can start to use it.
authored
73 URL = <<"https://friendpaste.com">>,
74 Headers = [],
75 Payload = <<>>,
76 Options = [],
c7600e1 @benoitc fix typos
authored
77 {ok, StatusCode, RespHeaders, Client} = hackney:request(Method, URL,
78 Headers, Payload,
79 Options).</pre>
b0fc869 @benoitc improve the readme so people can start to use it.
authored
80
81 The request method return the tupple `{ok, StatusCode, Headers, Client}`
82 or `{error, Reason}`.
83
84 If you enable the **parse_transform**, you can also do:<pre>hackney:get(URL, Headers, Payload, Options)</pre>
85
86 To enable parse transform add the following option to the erlang
25e1186 @benoitc regen
authored
87 compiler flags:<pre>{parse_transform, hackney_transform}</pre>
b0fc869 @benoitc improve the readme so people can start to use it.
authored
88
25e1186 @benoitc regen
authored
89 Alternately, you can add it to the module you wish to compile:<pre>-compile([{parse_transform, hackney_transform}]).</pre>
b0fc869 @benoitc improve the readme so people can start to use it.
authored
90
91 ### Read the body<pre>{ok, Body, Client1} = hackney:body(Client).</pre>
92
93 `hackney:body/1` fetch the body. To fetch it by chunk you can use the
94 `hackney:stream/body/1` function:<pre>read_body(MaxLength, Client, Acc) when MaxLength > byte_size(Acc) ->
95 case stream_body(Client) of
96 {ok, Data, Client2} ->
97 read_body(MaxLength, Client2, << Acc/binary, Data/binary >>);
98 {done, Client2} ->
99 {ok, Acc, Client2};
100 {error, Reason} ->
101 {error, Reason}
102 end.</pre>
103
104 ### Reuse the client object
105
106 If your connection support the keepalive you can reuse the Client
107 record using the `hackney:send_request/2` function:<pre>ReqBody = << "{
108 \"id\": \"some_paste_id\",
109 \"rev\": \"some_revision_id\",
110 \"changeset\": \"changeset in unidiff format\"
111 }" >>,
112 ReqHeaders = [{<<"Content-Type">>, <<"application/json">>}],
113 NextPath = <<"/">>,
114 NextMethod = post,
115 NextReq = {NextMethod, NextPath, ReqHeaders, ReqBody}
116 {ok, _, _, Client2} = hackney:send_request(Client1, NextReq).
117 {ok, Body1, Client3} = hackney:body(Client2),
118 hackney:close(Client3).</pre>
119
120 Here we are posting a JSON paylod to '/' on the service friendpaste to
121 create a paste. Then we close the client connection.
122
123 ### Send a body
124
125 hackney helps you send different payload by passing different terms as
126 the request body:
127
128 - `{form, PropList}` : To send a form
245d925 @benoitc don't force edown installation in prod. fix #10
authored
129 - `{multipart, KVs}` : to send you body using the multipart API. KVs can
130 be under the form `{file, Name, Content}` or `Value`
b0fc869 @benoitc improve the readme so people can start to use it.
authored
131 - `{file, File}` : To send a file
b754599 @benoitc forgot to regen the doc
authored
132 - Bin: To send a binary or an iolist
a231731 @benoitc add edown doc
authored
133
36255b7 @benoitc update readme
authored
134 > Note: to send a chunked request, just add the `Transfer-Encoding: chunked`
2022e7f @benoitc doc the follow redirection feature
authored
135 > header to your headers. Binary and Iolist bodies will be then sent using
36255b7 @benoitc update readme
authored
136 > the chunked encoding.
137
138 #### Send the body by yourself
139
140 While the default is to diretcly send the request and fetch the status
141 and headers if the body is set as the atom `stream` the request and
142 send_request function will return {ok, Client}. Then you can use the
143 function `hackney:stream_request_body/2` to stream the request body and
144 `hackney:start_response/1` to initialize the respone.
145
146 The function `hackney:start_response/1` is waiting a Client with
147 theresponse state equal to the atom `waiting`.
148
149 ex:<pre>ReqBody = << "{
150 \"id\": \"some_paste_id2\",
151 \"rev\": \"some_revision_id\",
152 \"changeset\": \"changeset in unidiff format\"
153 }" >>,
154 ReqHeaders = [{<<"Content-Type">>, <<"application/json">>}],
155 Path = <<"https://friendpaste.com/">>,
156 Method = post,
157 {ok, Client} = hackney:request(Method, Path, ReqHeaders, stream,
158 []),
159
160 {ok, Client1} = hackney:stream_request_body(ReqBody, Client),
161 {ok, _Status, _Headers, Client2} = hackney:start_response(Client1),
162 {ok, Body, Client3} = hackney:body(Client2),
163 hackney:close(Client3).</pre>
164
7d72c55 @benoitc add functions to change options of a pool
authored
165 ### Use a pool
166
167 To reuse a connection globally in your application you can also use a
168 socket pool. On startup, hackney launch a pool named default. To use it
cdd4ba2 @benoitc fix overview
authored
169 do the following:<pre>Method = get,
7d72c55 @benoitc add functions to change options of a pool
authored
170 URL = <<"https://friendpaste.com">>,
171 Headers = [],
172 Payload = <<>>,
173 Options = [{pool, default}],
174 {ok, StatusCode, RespHeaders, Client} = hackney:request(Method, URL, Headers,
175 Payload, Options).</pre>
176
177 By adding the tuple `{pool, default}` to the options, hackney will use
178 the connections stored in that pool.
179
180 You can also use different pools in your application which will allows
cdd4ba2 @benoitc fix overview
authored
181 you to maintain some kind of group of connections.<pre>PoolName = mypool,
7d72c55 @benoitc add functions to change options of a pool
authored
182 Options = [{timeout, 150000}, {pool_size, 100}],
cdd4ba2 @benoitc fix overview
authored
183 {ok, Pid} = hackney:start_pool(PoolName, Options),</pre>
7d72c55 @benoitc add functions to change options of a pool
authored
184
185 `timeout` is the time we keep alive the conneciton in the pool,
186 `pool_size` is the number of connections maintained in the pool. Each
187 connection in a pool is monitored and closed connections are removed
188 automatically.
189
190 To close a pool do:<pre>hackney:stop_pool(PoolName).</pre>
191
36255b7 @benoitc update readme
authored
192 > Note: Sometimes you want to always use the default pool in your app
193 > without having to set the client option each time. You can now do this
194 > by setting the hackney application environment key `use_default_pool`
195 > to true .
196
2022e7f @benoitc doc the follow redirection feature
authored
197 ### Automatically follow a redirection.
198
199 If the option `{follow_redirect, true}` is given to the request, the
200 client will be abble to automatically follow the redirection and
201 retrieve the body. The maximum number of connection can be set using the
202 `{max_redirect, Max}` option. Default is 5.
203
204 The client will follow redirection on 301, 302 & 307 if the method is
205 get or head. If another method is used the tuple
206 `{ok, maybe_redirect, Status, Headers, Client}` will be returned. It
207 only follow 303 redirection (see other) if the method is a POST.
208
209 Last Location is stored in the client state in the `location` property.
210
211 ex:<pre>Method = get,
212 URL = "http://friendpaste.com/",
213 ReqHeaders = [{<<"accept-encoding">>, <<"identity">>}],
214 ReqBody = <<>>,
215 Options = [{follow_redirect, true}, {max_redirect, true}],
216 {ok, S, H, Client} = hackney:request(Method, URL, ReqHeaders,
217 ReqBody, Options),
53c25a2 @benoitc typo
authored
218 {ok, Body, Client1} = hackney:body(Client).</pre>
219
9c20401 @benoitc describe the HTTP proxy tunneling
authored
220 ### Proxy a connection
221
222 For now only HTTP tunneling is supported. To use an HTTP tunnel add the
223 option `{proxy, ProxyUrl}` where `ProxyUrl` can be a simple url or an
224 `{Host, Port}` tuple. If you need to authetnicate set the option
225 `{proxy_auth, {User, Password}}`.
226
69249e8 @benoitc fix issue link
authored
227 ## Contribute
a231731 @benoitc add edown doc
authored
228
69249e8 @benoitc fix issue link
authored
229 For issues, comments or feedback please [create an
230 issue](http://github.com/benoitc/hackney/issues).
a231731 @benoitc add edown doc
authored
231
a04d1f3 @benoitc bump
authored
232 ### Notes for developers
245d925 @benoitc don't force edown installation in prod. fix #10
authored
233
234 If you want to contribute patches or improve the doc, you will need to
235 build hackney using the `rebar_dev.config` file. It can also be built
236 using the **Makefile**:<pre>$ make dev ; # compile & get deps
237 $ make devclean ; # clean all files</pre>
238
a231731 @benoitc add edown doc
authored
239 ##Modules##
240
241
242 <table width="100%" border="0" summary="list of modules">
5a47314 @benoitc document options
authored
243 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney.md" class="module">hackney</a></td></tr>
244 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_app.md" class="module">hackney_app</a></td></tr>
245 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_deps.md" class="module">hackney_deps</a></td></tr>
246 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_form.md" class="module">hackney_form</a></td></tr>
247 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_headers.md" class="module">hackney_headers</a></td></tr>
248 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_multipart.md" class="module">hackney_multipart</a></td></tr>
249 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_pool.md" class="module">hackney_pool</a></td></tr>
250 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_request.md" class="module">hackney_request</a></td></tr>
251 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_response.md" class="module">hackney_response</a></td></tr>
252 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_ssl_transport.md" class="module">hackney_ssl_transport</a></td></tr>
253 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_sup.md" class="module">hackney_sup</a></td></tr>
254 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_tcp_transport.md" class="module">hackney_tcp_transport</a></td></tr>
255 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_transform.md" class="module">hackney_transform</a></td></tr>
256 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_url.md" class="module">hackney_url</a></td></tr>
257 <tr><td><a href="http://github.com/benoitc/hackney/blob/master/doc/hackney_util.md" class="module">hackney_util</a></td></tr></table>
a231731 @benoitc add edown doc
authored
258
Something went wrong with that request. Please try again.