Imported Upstream version 1.41.0
[platform/upstream/nghttp2.git] / doc / sources / tutorial-client.rst
1 Tutorial: HTTP/2 client
2 =========================
3
4 In this tutorial, we are going to write a very primitive HTTP/2
5 client. The complete source code, `libevent-client.c`_, is attached at
6 the end of this page.  It also resides in the examples directory in
7 the archive or repository.
8
9 This simple client takes a single HTTPS URI and retrieves the resource
10 at the URI. The synopsis is:
11
12 .. code-block:: text
13
14     $ libevent-client HTTPS_URI
15
16 We use libevent in this tutorial to handle networking I/O.  Please
17 note that nghttp2 itself does not depend on libevent.
18
19 The client starts with some libevent and OpenSSL setup in the
20 ``main()`` and ``run()`` functions. This setup isn't specific to
21 nghttp2, but one thing you should look at is setup of the NPN
22 callback.  The NPN callback is used by the client to select the next
23 application protocol over TLS. In this tutorial, we use the
24 `nghttp2_select_next_protocol()` helper function to select the HTTP/2
25 protocol the library supports::
26
27     static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
28                                     unsigned char *outlen, const unsigned char *in,
29                                     unsigned int inlen, void *arg _U_) {
30       if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
31         errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
32       }
33       return SSL_TLSEXT_ERR_OK;
34     }
35
36 If you are following TLS related RFC, you know that NPN is not the
37 standardized way to negotiate HTTP/2.  NPN itself is not event
38 published as RFC.  The standard way to negotiate HTTP/2 is ALPN,
39 Application-Layer Protocol Negotiation Extension, defined in `RFC 7301
40 <https://tools.ietf.org/html/rfc7301>`_.  The one caveat of ALPN is
41 that OpenSSL >= 1.0.2 is required.  We use macro to enable/disable
42 ALPN support depending on OpenSSL version.  OpenSSL's ALPN
43 implementation does not require callback function like the above.  But
44 we have to instruct OpenSSL SSL_CTX to use ALPN, which we'll talk
45 about soon.
46
47 The callback is added to the SSL_CTX object using
48 ``SSL_CTX_set_next_proto_select_cb()``::
49
50     static SSL_CTX *create_ssl_ctx(void) {
51       SSL_CTX *ssl_ctx;
52       ssl_ctx = SSL_CTX_new(SSLv23_client_method());
53       if (!ssl_ctx) {
54         errx(1, "Could not create SSL/TLS context: %s",
55              ERR_error_string(ERR_get_error(), NULL));
56       }
57       SSL_CTX_set_options(ssl_ctx,
58                           SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
59                               SSL_OP_NO_COMPRESSION |
60                               SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
61       SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
62
63     #if OPENSSL_VERSION_NUMBER >= 0x10002000L
64       SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
65     #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
66
67       return ssl_ctx;
68     }
69
70 Here we see ``SSL_CTX_get_alpn_protos()`` function call.  We instructs
71 OpenSSL to notify the server that we support h2, ALPN identifier for
72 HTTP/2.
73
74 The example client defines a couple of structs:
75
76 We define and use a ``http2_session_data`` structure to store data
77 related to the HTTP/2 session::
78
79     typedef struct {
80       nghttp2_session *session;
81       struct evdns_base *dnsbase;
82       struct bufferevent *bev;
83       http2_stream_data *stream_data;
84     } http2_session_data;
85
86 Since this program only handles one URI, it uses only one stream. We
87 store the single stream's data in a ``http2_stream_data`` structure
88 and the ``stream_data`` points to it. The ``http2_stream_data``
89 structure is defined as follows::
90
91     typedef struct {
92       /* The NULL-terminated URI string to retrieve. */
93       const char *uri;
94       /* Parsed result of the |uri| */
95       struct http_parser_url *u;
96       /* The authority portion of the |uri|, not NULL-terminated */
97       char *authority;
98       /* The path portion of the |uri|, including query, not
99          NULL-terminated */
100       char *path;
101       /* The length of the |authority| */
102       size_t authoritylen;
103       /* The length of the |path| */
104       size_t pathlen;
105       /* The stream ID of this stream */
106       int32_t stream_id;
107     } http2_stream_data;
108
109 We create and initialize these structures in
110 ``create_http2_session_data()`` and ``create_http2_stream_data()``
111 respectively.
112
113 ``initiate_connection()`` is called to start the connection to the
114 remote server. It's defined as::
115
116     static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
117                                     const char *host, uint16_t port,
118                                     http2_session_data *session_data) {
119       int rv;
120       struct bufferevent *bev;
121       SSL *ssl;
122
123       ssl = create_ssl(ssl_ctx);
124       bev = bufferevent_openssl_socket_new(
125           evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
126           BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
127       bufferevent_enable(bev, EV_READ | EV_WRITE);
128       bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
129       rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
130                                                AF_UNSPEC, host, port);
131
132       if (rv != 0) {
133         errx(1, "Could not connect to the remote host %s", host);
134       }
135       session_data->bev = bev;
136     }
137
138 ``initiate_connection()`` creates a bufferevent for the connection and
139 sets up three callbacks: ``readcb``, ``writecb``, and ``eventcb``.
140
141 The ``eventcb()`` is invoked by the libevent event loop when an event
142 (e.g. connection has been established, timeout, etc.) occurs on the
143 underlying network socket::
144
145     static void eventcb(struct bufferevent *bev, short events, void *ptr) {
146       http2_session_data *session_data = (http2_session_data *)ptr;
147       if (events & BEV_EVENT_CONNECTED) {
148         int fd = bufferevent_getfd(bev);
149         int val = 1;
150         const unsigned char *alpn = NULL;
151         unsigned int alpnlen = 0;
152         SSL *ssl;
153
154         fprintf(stderr, "Connected\n");
155
156         ssl = bufferevent_openssl_get_ssl(session_data->bev);
157
158         SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
159     #if OPENSSL_VERSION_NUMBER >= 0x10002000L
160         if (alpn == NULL) {
161           SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
162         }
163     #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
164
165         if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
166           fprintf(stderr, "h2 is not negotiated\n");
167           delete_http2_session_data(session_data);
168           return;
169         }
170
171         setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
172         initialize_nghttp2_session(session_data);
173         send_client_connection_header(session_data);
174         submit_request(session_data);
175         if (session_send(session_data) != 0) {
176           delete_http2_session_data(session_data);
177         }
178         return;
179       }
180       if (events & BEV_EVENT_EOF) {
181         warnx("Disconnected from the remote host");
182       } else if (events & BEV_EVENT_ERROR) {
183         warnx("Network error");
184       } else if (events & BEV_EVENT_TIMEOUT) {
185         warnx("Timeout");
186       }
187       delete_http2_session_data(session_data);
188     }
189
190 Here we validate that HTTP/2 is negotiated, and if not, drop
191 connection.
192
193 For ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR``, and ``BEV_EVENT_TIMEOUT``
194 events, we just simply tear down the connection.
195
196 The ``BEV_EVENT_CONNECTED`` event is invoked when the SSL/TLS
197 handshake has completed successfully. After this we're ready to begin
198 communicating via HTTP/2.
199
200 The ``initialize_nghttp2_session()`` function initializes the nghttp2
201 session object and several callbacks::
202
203     static void initialize_nghttp2_session(http2_session_data *session_data) {
204       nghttp2_session_callbacks *callbacks;
205
206       nghttp2_session_callbacks_new(&callbacks);
207
208       nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
209
210       nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
211                                                            on_frame_recv_callback);
212
213       nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
214           callbacks, on_data_chunk_recv_callback);
215
216       nghttp2_session_callbacks_set_on_stream_close_callback(
217           callbacks, on_stream_close_callback);
218
219       nghttp2_session_callbacks_set_on_header_callback(callbacks,
220                                                        on_header_callback);
221
222       nghttp2_session_callbacks_set_on_begin_headers_callback(
223           callbacks, on_begin_headers_callback);
224
225       nghttp2_session_client_new(&session_data->session, callbacks, session_data);
226
227       nghttp2_session_callbacks_del(callbacks);
228     }
229
230 Since we are creating a client, we use `nghttp2_session_client_new()`
231 to initialize the nghttp2 session object.  The callbacks setup are
232 explained later.
233
234 The `delete_http2_session_data()` function destroys ``session_data``
235 and frees its bufferevent, so the underlying connection is closed. It
236 also calls `nghttp2_session_del()` to delete the nghttp2 session
237 object.
238
239 A HTTP/2 connection begins by sending the client connection preface,
240 which is a 24 byte magic byte string (:macro:`NGHTTP2_CLIENT_MAGIC`),
241 followed by a SETTINGS frame. The 24 byte magic string is sent
242 automatically by nghttp2. We send the SETTINGS frame in
243 ``send_client_connection_header()``::
244
245     static void send_client_connection_header(http2_session_data *session_data) {
246       nghttp2_settings_entry iv[1] = {
247           {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
248       int rv;
249
250       /* client 24 bytes magic string will be sent by nghttp2 library */
251       rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
252                                    ARRLEN(iv));
253       if (rv != 0) {
254         errx(1, "Could not submit SETTINGS: %s", nghttp2_strerror(rv));
255       }
256     }
257
258 Here we specify SETTINGS_MAX_CONCURRENT_STREAMS as 100. This is not
259 needed for this tiny example program, it just demonstrates use of the
260 SETTINGS frame. To queue the SETTINGS frame for transmission, we call
261 `nghttp2_submit_settings()`. Note that `nghttp2_submit_settings()`
262 only queues the frame for transmission, and doesn't actually send it.
263 All ``nghttp2_submit_*()`` family functions have this property. To
264 actually send the frame, `nghttp2_session_send()` has to be called,
265 which is described (and called) later.
266
267 After the transmission of the client connection header, we enqueue the
268 HTTP request in the ``submit_request()`` function::
269
270     static void submit_request(http2_session_data *session_data) {
271       int32_t stream_id;
272       http2_stream_data *stream_data = session_data->stream_data;
273       const char *uri = stream_data->uri;
274       const struct http_parser_url *u = stream_data->u;
275       nghttp2_nv hdrs[] = {
276           MAKE_NV2(":method", "GET"),
277           MAKE_NV(":scheme", &uri[u->field_data[UF_SCHEMA].off],
278                   u->field_data[UF_SCHEMA].len),
279           MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
280           MAKE_NV(":path", stream_data->path, stream_data->pathlen)};
281       fprintf(stderr, "Request headers:\n");
282       print_headers(stderr, hdrs, ARRLEN(hdrs));
283       stream_id = nghttp2_submit_request(session_data->session, NULL, hdrs,
284                                          ARRLEN(hdrs), NULL, stream_data);
285       if (stream_id < 0) {
286         errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id));
287       }
288
289       stream_data->stream_id = stream_id;
290     }
291
292 We build the HTTP request header fields in ``hdrs``, which is an array
293 of :type:`nghttp2_nv`. There are four header fields to be sent:
294 ``:method``, ``:scheme``, ``:authority``, and ``:path``. To queue the
295 HTTP request, we call `nghttp2_submit_request()`. The ``stream_data``
296 is passed via the *stream_user_data* parameter, which is helpfully
297 later passed back to callback functions.
298
299 `nghttp2_submit_request()` returns the newly assigned stream ID for
300 the request.
301
302 The next bufferevent callback is ``readcb()``, which is invoked when
303 data is available to read from the bufferevent input buffer::
304
305     static void readcb(struct bufferevent *bev, void *ptr) {
306       http2_session_data *session_data = (http2_session_data *)ptr;
307       ssize_t readlen;
308       struct evbuffer *input = bufferevent_get_input(bev);
309       size_t datalen = evbuffer_get_length(input);
310       unsigned char *data = evbuffer_pullup(input, -1);
311
312       readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
313       if (readlen < 0) {
314         warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
315         delete_http2_session_data(session_data);
316         return;
317       }
318       if (evbuffer_drain(input, (size_t)readlen) != 0) {
319         warnx("Fatal error: evbuffer_drain failed");
320         delete_http2_session_data(session_data);
321         return;
322       }
323       if (session_send(session_data) != 0) {
324         delete_http2_session_data(session_data);
325         return;
326       }
327     }
328
329 In this function we feed all unprocessed, received data to the nghttp2
330 session object using the `nghttp2_session_mem_recv()` function.
331 `nghttp2_session_mem_recv()` processes the received data and may
332 invoke nghttp2 callbacks and queue frames for transmission.  Since
333 there may be pending frames for transmission, we call immediately
334 ``session_send()`` to send them.  ``session_send()`` is defined as
335 follows::
336
337     static int session_send(http2_session_data *session_data) {
338       int rv;
339
340       rv = nghttp2_session_send(session_data->session);
341       if (rv != 0) {
342         warnx("Fatal error: %s", nghttp2_strerror(rv));
343         return -1;
344       }
345       return 0;
346     }
347
348 The `nghttp2_session_send()` function serializes pending frames into
349 wire format and calls the ``send_callback()`` function to send them.
350 ``send_callback()`` has type :type:`nghttp2_send_callback` and is
351 defined as::
352
353     static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
354                                  size_t length, int flags _U_, void *user_data) {
355       http2_session_data *session_data = (http2_session_data *)user_data;
356       struct bufferevent *bev = session_data->bev;
357       bufferevent_write(bev, data, length);
358       return (ssize_t)length;
359     }
360
361 Since we use bufferevent to abstract network I/O, we just write the
362 data to the bufferevent object. Note that `nghttp2_session_send()`
363 continues to write all frames queued so far. If we were writing the
364 data to the non-blocking socket directly using the ``write()`` system
365 call, we'd soon receive an ``EAGAIN`` or ``EWOULDBLOCK`` error, since
366 sockets have a limited send buffer. If that happens, it's possible to
367 return :macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the nghttp2 library
368 to stop sending further data. When writing to a bufferevent, you
369 should regulate the amount of data written, to avoid possible huge
370 memory consumption. In this example client however we don't implement
371 a limit. To see how to regulate the amount of buffered data, see the
372 ``send_callback()`` in the server tutorial.
373
374 The third bufferevent callback is ``writecb()``, which is invoked when
375 all data written in the bufferevent output buffer has been sent::
376
377     static void writecb(struct bufferevent *bev _U_, void *ptr) {
378       http2_session_data *session_data = (http2_session_data *)ptr;
379       if (nghttp2_session_want_read(session_data->session) == 0 &&
380           nghttp2_session_want_write(session_data->session) == 0 &&
381           evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
382         delete_http2_session_data(session_data);
383       }
384     }
385
386 As described earlier, we just write off all data in `send_callback()`,
387 so there is no data to write in this function. All we have to do is
388 check if the connection should be dropped or not. The nghttp2 session
389 object keeps track of reception and transmission of GOAWAY frames and
390 other error conditions. Using this information, the nghttp2 session
391 object can state whether the connection should be dropped or not.
392 More specifically, when both `nghttp2_session_want_read()` and
393 `nghttp2_session_want_write()` return 0, the connection is no-longer
394 required and can be closed. Since we're using bufferevent and its
395 deferred callback option, the bufferevent output buffer may still
396 contain pending data when the ``writecb()`` is called. To handle this
397 situation, we also check whether the output buffer is empty or not. If
398 all of these conditions are met, then we drop the connection.
399
400 Now let's look at the remaining nghttp2 callbacks setup in the
401 ``initialize_nghttp2_setup()`` function.
402
403 A server responds to the request by first sending a HEADERS frame.
404 The HEADERS frame consists of response header name/value pairs, and
405 the ``on_header_callback()`` is called for each name/value pair::
406
407     static int on_header_callback(nghttp2_session *session _U_,
408                                   const nghttp2_frame *frame, const uint8_t *name,
409                                   size_t namelen, const uint8_t *value,
410                                   size_t valuelen, uint8_t flags _U_,
411                                   void *user_data) {
412       http2_session_data *session_data = (http2_session_data *)user_data;
413       switch (frame->hd.type) {
414       case NGHTTP2_HEADERS:
415         if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
416             session_data->stream_data->stream_id == frame->hd.stream_id) {
417           /* Print response headers for the initiated request. */
418           print_header(stderr, name, namelen, value, valuelen);
419           break;
420         }
421       }
422       return 0;
423     }
424
425 In this tutorial, we just print the name/value pairs on stderr.
426
427 After the HEADERS frame has been fully received (and thus all response
428 header name/value pairs have been received), the
429 ``on_frame_recv_callback()`` function is called::
430
431     static int on_frame_recv_callback(nghttp2_session *session _U_,
432                                       const nghttp2_frame *frame, void *user_data) {
433       http2_session_data *session_data = (http2_session_data *)user_data;
434       switch (frame->hd.type) {
435       case NGHTTP2_HEADERS:
436         if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
437             session_data->stream_data->stream_id == frame->hd.stream_id) {
438           fprintf(stderr, "All headers received\n");
439         }
440         break;
441       }
442       return 0;
443     }
444
445 ``on_frame_recv_callback()`` is called for other frame types too.
446
447 In this tutorial, we are just interested in the HTTP response HEADERS
448 frame. We check the frame type and its category (it should be
449 :macro:`NGHTTP2_HCAT_RESPONSE` for HTTP response HEADERS). We also
450 check its stream ID.
451
452 Next, zero or more DATA frames can be received. The
453 ``on_data_chunk_recv_callback()`` function is invoked when a chunk of
454 data is received from the remote peer::
455
456     static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
457                                            uint8_t flags _U_, int32_t stream_id,
458                                            const uint8_t *data, size_t len,
459                                            void *user_data) {
460       http2_session_data *session_data = (http2_session_data *)user_data;
461       if (session_data->stream_data->stream_id == stream_id) {
462         fwrite(data, len, 1, stdout);
463       }
464       return 0;
465     }
466
467 In our case, a chunk of data is HTTP response body. After checking the
468 stream ID, we just write the received data to stdout. Note the output
469 in the terminal may be corrupted if the response body contains some
470 binary data.
471
472 The ``on_stream_close_callback()`` function is invoked when the stream
473 is about to close::
474
475     static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
476                                         nghttp2_error_code error_code,
477                                         void *user_data) {
478       http2_session_data *session_data = (http2_session_data *)user_data;
479       int rv;
480
481       if (session_data->stream_data->stream_id == stream_id) {
482         fprintf(stderr, "Stream %d closed with error_code=%d\n", stream_id,
483                 error_code);
484         rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
485         if (rv != 0) {
486           return NGHTTP2_ERR_CALLBACK_FAILURE;
487         }
488       }
489       return 0;
490     }
491
492 If the stream ID matches the one we initiated, it means that its
493 stream is going to be closed. Since we have finished receiving
494 resource we wanted (or the stream was reset by RST_STREAM from the
495 remote peer), we call `nghttp2_session_terminate_session()` to
496 commence closure of the HTTP/2 session gracefully. If you have
497 some data associated for the stream to be closed, you may delete it
498 here.