Imported Upstream version 1.0.0
[platform/upstream/nghttp2.git] / doc / sources / libnghttp2_asio.rst
1 libnghttp2_asio: High level HTTP/2 C++ library
2 ==============================================
3
4 libnghttp2_asio is C++ library built on top of libnghttp2 and provides
5 high level abstraction API to build HTTP/2 applications.  It depends
6 on Boost::ASIO library and OpenSSL.  Currently libnghttp2_asio
7 provides server and client side API.
8
9 libnghttp2_asio is not built by default.  Use ``--enable-asio-lib``
10 configure flag to build libnghttp2_asio.  The required Boost libraries
11 are:
12
13 * Boost::Asio
14 * Boost::System
15 * Boost::Thread
16
17 We have 3 header files for this library:
18
19 * :doc:`asio_http2_server.h`
20 * :doc:`asio_http2_client.h`
21 * :doc:`asio_http2.h`
22
23 asio_http2.h is included from the other two files.
24
25 To build a program with libnghttp2_asio, link to the following
26 libraries::
27
28     -lnghttp2_asio -lboost_system
29
30 If ``boost::asio::ssl`` is used in application code, OpenSSL is also
31 required in link line::
32
33     -lnghttp2_asio -lboost_system -lssl -lcrypto
34
35 Server API
36 ----------
37
38 To use server API, first include following header file:
39
40 .. code-block:: cpp
41
42     #include <nghttp2/asio_http2_server.h>
43
44 Also take a look at that header file :doc:`asio_http2_server.h`.
45
46 Server API is designed to build HTTP/2 server very easily to utilize
47 C++11 anonymous function and closure.  The bare minimum example of
48 HTTP/2 server looks like this:
49
50 .. code-block:: cpp
51
52     using namespace nghttp2::asio_http2;
53     using namespace nghttp2::asio_http2::server;
54
55     int main(int argc, char *argv[]) {
56       boost::system::error_code ec;
57       http2 server;
58
59       server.handle("/", [](const request &req, const response &res) {
60         res.write_head(200);
61         res.end("hello, world\n");
62       });
63
64       if (server.listen_and_serve(ec, "localhost", "3000")) {
65         std::cerr << "error: " << ec.message() << std::endl;
66       }
67     }
68
69 First we instantiate ``nghttp2::asio_http2::server::http2`` object.
70 ``nghttp2::asio_http2::server::http2::handle`` function registers
71 pattern and its handler function.  In this example, we register "/" as
72 pattern, which matches all requests.  Then call
73 ``nghttp2::asio_http2::server::http2::listen_and_serve`` function with
74 address and port to listen to.
75
76 The ``req`` and ``res`` represent HTTP request and response
77 respectively.  ``nghttp2::asio_http2_::server::response::write_head``
78 constructs HTTP response header fields.  The first argument is HTTP
79 status code, in the above example, which is 200.  The second argument,
80 which is omitted in the above example, is additional header fields to
81 send.
82
83 ``nghttp2::asio_http2::server::response::end`` sends response body.
84 In the above example, we send string "hello, world".
85
86 The life time of req and res object ends after the callback set by
87 ``nghttp2::asio_http2::server::response::on_close`` function.
88 Application must not use those objects after this call.
89
90 Serving static files and enabling SSL/TLS
91 +++++++++++++++++++++++++++++++++++++++++
92
93 In this example, we serve a couple of static files and also enable
94 SSL/TLS.
95
96 .. code-block:: cpp
97
98     #include <nghttp2/asio_http2_server.h>
99
100     using namespace nghttp2::asio_http2;
101     using namespace nghttp2::asio_http2::server;
102
103     int main(int argc, char *argv[]) {
104       boost::system::error_code ec;
105       boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
106
107       tls.use_private_key_file("server.key", boost::asio::ssl::context::pem);
108       tls.use_certificate_chain_file("server.crt");
109
110       configure_tls_context_easy(ec, tls);
111
112       http2 server;
113
114       server.handle("/index.html", [](const request &req, const response &res) {
115         res.write_head(200);
116         res.end(file_generator("index.html"));
117       });
118
119       if (server.listen_and_serve(ec, tls, "localhost", "3000")) {
120         std::cerr << "error: " << ec.message() << std::endl;
121       }
122     }
123
124 We first create ``boost::asio::ssl::context`` object and set path to
125 private key file and certificate file.
126 ``nghttp2::asio_http2::server::configure_tls_context_easy`` function
127 configures SSL/TLS context object for HTTP/2 server use, including NPN
128 callbacks.
129
130 In the above example, if request path is "/index.html", we serve
131 index.html file in the current working directory.
132 ``nghttp2::asio_http2::server::response::end`` has overload to take
133 function of type ``nghttp2::asio_http2::generator_cb`` and application
134 pass its implementation to generate response body.  For the
135 convenience, libnghttp2_asio library provides
136 ``nghttp2::asio_http2::file_generator`` function to generate function
137 to server static file.  If other resource is requested, server
138 automatically responds with 404 status code.
139
140 Server push
141 +++++++++++
142
143 Server push is also supported.
144
145 .. code-block:: cpp
146
147     #include <nghttp2/asio_http2_server.h>
148
149     using namespace nghttp2::asio_http2;
150     using namespace nghttp2::asio_http2::server;
151
152     int main(int argc, char *argv[]) {
153       boost::system::error_code ec;
154       boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
155
156       tls.use_private_key_file("server.key", boost::asio::ssl::context::pem);
157       tls.use_certificate_chain_file("server.crt");
158
159       configure_tls_context_easy(ec, tls);
160
161       http2 server;
162
163       std::string style_css = "h1 { color: green; }";
164
165       server.handle("/", [&style_css](const request &req, const response &res) {
166         boost::system::error_code ec;
167         auto push = res.push(ec, "GET", "/style.css");
168         push->write_head(200);
169         push->end(style_css);
170
171         res.write_head(200);
172         res.end(R"(
173     <!DOCTYPE html><html lang="en">
174     <title>HTTP/2 FTW</title><body>
175     <link href="/style.css" rel="stylesheet" type="text/css">
176     <h1>This should be green</h1>
177     </body></html>
178     )");
179       });
180
181       server.handle("/style.css",
182                     [&style_css](const request &req, const response &res) {
183         res.write_head(200);
184         res.end(style_css);
185       });
186
187       if (server.listen_and_serve(ec, tls, "localhost", "3000")) {
188         std::cerr << "error: " << ec.message() << std::endl;
189       }
190     }
191
192 When client requested any resource other than "/style.css", we push
193 "/style.css".  To push resource, call
194 ``nghttp2::asio_http2::server::response::push`` function with desired
195 method and path.  It returns another response object and use its
196 functions to send push response.
197
198 Enable multi-threading
199 ++++++++++++++++++++++
200
201 Enabling multi-threading is very easy.  Just call
202 ``nghttp2::asio_http2::server::http2::num_threads`` function with the
203 desired number of threads:
204
205 .. code-block:: cpp
206
207     http2 server;
208
209     // Use 4 native threads
210     server.num_threads(4);
211
212 Client API
213 ----------
214
215 To use client API, first include following header file:
216
217 .. code-block:: cpp
218
219     #include <nghttp2/asio_http2_client.h>
220
221 Also take a look at that header file :doc:`asio_http2_client.h`.
222
223 Here is the sample client code to access HTTP/2 server and print out
224 response header fields and response body to the console screen:
225
226 .. code-block:: cpp
227
228     #include <iostream>
229
230     #include <nghttp2/asio_http2_client.h>
231
232     using boost::asio::ip::tcp;
233
234     using namespace nghttp2::asio_http2;
235     using namespace nghttp2::asio_http2::client;
236
237     int main(int argc, char *argv[]) {
238       boost::system::error_code ec;
239       boost::asio::io_service io_service;
240
241       // connect to localhost:3000
242       session sess(io_service, "localhost", "3000");
243
244       sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
245         boost::system::error_code ec;
246
247         auto req = sess.submit(ec, "GET", "http://localhost:3000/");
248
249         req->on_response([](const response &res) {
250           // print status code and response header fields.
251           std::cerr << "HTTP/2 " << res.status_code() << std::endl;
252           for (auto &kv : res.header()) {
253             std::cerr << kv.first << ": " << kv.second.value << "\n";
254           }
255           std::cerr << std::endl;
256
257           res.on_data([](const uint8_t *data, std::size_t len) {
258             std::cerr.write(reinterpret_cast<const char *>(data), len);
259             std::cerr << std::endl;
260           });
261         });
262
263         req->on_close([&sess](uint32_t error_code) {
264           // shutdown session after first request was done.
265           sess.shutdown();
266         });
267       });
268
269       sess.on_error([](const boost::system::error_code &ec) {
270         std::cerr << "error: " << ec.message() << std::endl;
271       });
272
273       io_service.run();
274     }
275
276 ``nghttp2::asio_http2::client::session`` object takes
277 ``boost::asio::io_service`` object and remote server address.  When
278 connection is made, the callback function passed to
279 ``nghttp2::asio_http2::client::on_connect`` is invoked with connected
280 address as its parameter.  After this callback call, use
281 ``nghttp2::asio_http2::session::submit`` to send request to the
282 server.  You can submit multiple requests at once without waiting for
283 the completion of previous request.
284
285 The life time of req and res object ends after the callback set by
286 ``nghttp2::asio_http2::server::request::on_close`` function.
287 Application must not use those objects after this call.
288
289 Normally, client does not stop even after all requests are done unless
290 connection is lost.  To stop client, call
291 ``nghttp2::asio_http2::server::session::shutdown()``.
292
293 Recieve server push and enable SSL/TLS
294 ++++++++++++++++++++++++++++++++++++++
295
296 .. code-block:: cpp
297
298     #include <iostream>
299
300     #include <nghttp2/asio_http2_client.h>
301
302     using boost::asio::ip::tcp;
303
304     using namespace nghttp2::asio_http2;
305     using namespace nghttp2::asio_http2::client;
306
307     int main(int argc, char *argv[]) {
308       boost::system::error_code ec;
309       boost::asio::io_service io_service;
310
311       boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
312       tls.set_default_verify_paths();
313       // disabled to make development easier...
314       // tls_ctx.set_verify_mode(boost::asio::ssl::verify_peer);
315       configure_tls_context(ec, tls);
316
317       // connect to localhost:3000
318       session sess(io_service, tls, "localhost", "3000");
319
320       sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
321         boost::system::error_code ec;
322
323         auto req = sess.submit(ec, "GET", "http://localhost:3000/");
324
325         req->on_response([&sess](const response &res) {
326           std::cerr << "response received!" << std::endl;
327           res.on_data([&sess](const uint8_t *data, std::size_t len) {
328             std::cerr.write(reinterpret_cast<const char *>(data), len);
329             std::cerr << std::endl;
330           });
331         });
332
333         req->on_push([](const request &push) {
334           std::cerr << "push request received!" << std::endl;
335           push.on_response([](const response &res) {
336             std::cerr << "push response received!" << std::endl;
337             res.on_data([](const uint8_t *data, std::size_t len) {
338               std::cerr.write(reinterpret_cast<const char *>(data), len);
339               std::cerr << std::endl;
340             });
341           });
342         });
343       });
344
345       sess.on_error([](const boost::system::error_code &ec) {
346         std::cerr << "error: " << ec.message() << std::endl;
347       });
348
349       io_service.run();
350     }
351
352 The above sample code demonstrates how to enable SSL/TLS and receive
353 server push.  Currently,
354 ``nghttp2::asio_http2::client::configure_tls_context`` function setups
355 NPN callbacks for SSL/TLS context for HTTP/2 use.
356
357 To receive server push, use
358 ``nghttp2::asio_http2::client::request::on_push`` function to set
359 callback function which is invoked when server push request is
360 arrived.  The callback function takes
361 ``nghttp2::asio_http2::client::request`` object, which contains the
362 pushed request.  To get server push response, set callback using
363 ``nghttp2::asio_http2::client::request::on_response``.
364
365 As stated in the previous section, client does not stop automatically
366 as long as HTTP/2 session is fine and connection is alive.  We don't
367 call ``nghttp2::asio_http2::client::session::shutdown`` in this
368 example, so the program does not terminate after all responses are
369 received.  Hit Ctrl-C to terminate the program.
370
371 Multiple concurrent requests
372 ++++++++++++++++++++++++++++
373
374 .. code-block:: cpp
375
376     #include <iostream>
377
378     #include <nghttp2/asio_http2_client.h>
379
380     using boost::asio::ip::tcp;
381
382     using namespace nghttp2::asio_http2;
383     using namespace nghttp2::asio_http2::client;
384
385     int main(int argc, char *argv[]) {
386       boost::system::error_code ec;
387       boost::asio::io_service io_service;
388
389       // connect to localhost:3000
390       session sess(io_service, "localhost", "3000");
391
392       sess.on_connect([&sess](tcp::resolver::iterator endpoint_it) {
393         boost::system::error_code ec;
394
395         auto printer = [](const response &res) {
396           res.on_data([](const uint8_t *data, std::size_t len) {
397             std::cerr.write(reinterpret_cast<const char *>(data), len);
398             std::cerr << std::endl;
399           });
400         };
401
402         std::size_t num = 3;
403         auto count = std::make_shared<int>(num);
404
405         for (std::size_t i = 0; i < num; ++i) {
406           auto req = sess.submit(ec, "GET",
407                                  "http://localhost:3000/" + std::to_string(i + 1));
408
409           req->on_response(printer);
410           req->on_close([&sess, count](uint32_t error_code) {
411             if (--*count == 0) {
412               // shutdown session after |num| requests were done.
413               sess.shutdown();
414             }
415           });
416         }
417       });
418
419       sess.on_error([](const boost::system::error_code &ec) {
420         std::cerr << "error: " << ec.message() << std::endl;
421       });
422
423       io_service.run();
424     }
425
426 Here is the sample to send 3 requests at once.  Depending on the
427 server settings, these requests are processed out-of-order.  In this
428 example, we have a trick to shutdown session after all requests were
429 done.  We made ``count`` object which is shared pointer to int and is
430 initialized to 3.  On each request closure (the invocation of the
431 callback set by ``nghttp2::asio_http2::client::request::on_close``),
432 we decrement the count.  If count becomes 0, we are sure that all
433 requests have been done and initiate shutdown.