1Programmers' Guide 2================== 3 4Architecture 5------------ 6 7The most notable point in nghttp2 library architecture is it does not 8perform any I/O. nghttp2 only performs HTTP/2 protocol stuff based on 9input byte strings. It will call callback functions set by 10applications while processing input. The output of nghttp2 is just 11byte string. An application is responsible to send these output to 12the remote peer. The callback functions may be called while producing 13output. 14 15Not doing I/O makes embedding nghttp2 library in the existing code 16base very easy. Usually, the existing applications have its own I/O 17event loops. It is very hard to use nghttp2 in that situation if 18nghttp2 does its own I/O. It also makes light weight language wrapper 19for nghttp2 easy with the same reason. The down side is that an 20application author has to write more code to write complete 21application using nghttp2. This is especially true for simple "toy" 22application. For the real applications, however, this is not the 23case. This is because you probably want to support HTTP/1 which 24nghttp2 does not provide, and to do that, you will need to write your 25own HTTP/1 stack or use existing third-party library, and bind them 26together with nghttp2 and I/O event loop. In this point, not 27performing I/O in nghttp2 has more point than doing it. 28 29The primary object that an application uses is :type:`nghttp2_session` 30object, which is opaque struct and its details are hidden in order to 31ensure the upgrading its internal architecture without breaking the 32backward compatibility. An application can set callbacks to 33:type:`nghttp2_session` object through the dedicated object and 34functions, and it also interacts with it via many API function calls. 35 36An application can create as many :type:`nghttp2_session` object as it 37wants. But single :type:`nghttp2_session` object must be used by a 38single thread at the same time. This is not so hard to enforce since 39most event-based architecture applications use is single thread per 40core, and handling one connection I/O is done by single thread. 41 42To feed input to :type:`nghttp2_session` object, one can use 43`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` functions. 44They behave similarly, and the difference is that 45`nghttp2_session_recv()` will use :type:`nghttp2_read_callback` to get 46input. On the other hand, `nghttp2_session_mem_recv()` will take 47input as its parameter. If in doubt, use `nghttp2_session_mem_recv()` 48since it is simpler, and could be faster since it avoids calling 49callback function. 50 51To get output from :type:`nghttp2_session` object, one can use 52`nghttp2_session_send()` or `nghttp2_session_mem_send()`. The 53difference between them is that the former uses 54:type:`nghttp2_send_callback` to pass output to an application. On 55the other hand, the latter returns the output to the caller. If in 56doubt, use `nghttp2_session_mem_send()` since it is simpler. But 57`nghttp2_session_send()` might be easier to use if the output buffer 58an application has is fixed sized. 59 60In general, an application should call `nghttp2_session_mem_send()` 61when it gets input from underlying connection. Since there is great 62chance to get something pushed into transmission queue while the call 63of `nghttp2_session_mem_send()`, it is recommended to call 64`nghttp2_session_mem_recv()` after `nghttp2_session_mem_send()`. 65 66There is a question when we are safe to close HTTP/2 session without 67waiting for the closure of underlying connection. We offer 2 API 68calls for this: `nghttp2_session_want_read()` and 69`nghttp2_session_want_write()`. If they both return 0, application 70can destroy :type:`nghttp2_session`, and then close the underlying 71connection. But make sure that the buffered output has been 72transmitted to the peer before closing the connection when 73`nghttp2_session_mem_send()` is used, since 74`nghttp2_session_want_write()` does not take into account the 75transmission of the buffered data outside of :type:`nghttp2_session`. 76 77Includes 78-------- 79 80To use the public APIs, include ``nghttp2/nghttp2.h``:: 81 82 #include <nghttp2/nghttp2.h> 83 84The header files are also available online: :doc:`nghttp2.h` and 85:doc:`nghttp2ver.h`. 86 87Remarks 88------- 89 90Do not call `nghttp2_session_send()`, `nghttp2_session_mem_send()`, 91`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` from the 92nghttp2 callback functions directly or indirectly. It will lead to the 93crash. You can submit requests or frames in the callbacks then call 94these functions outside the callbacks. 95 96`nghttp2_session_send()` and `nghttp2_session_mem_send()` send first 9724 bytes of client magic string (MAGIC) 98(:macro:`NGHTTP2_CLIENT_MAGIC`) on client configuration. The 99applications are responsible to send SETTINGS frame as part of 100connection preface using `nghttp2_submit_settings()`. Similarly, 101`nghttp2_session_recv()` and `nghttp2_session_mem_recv()` consume 102MAGIC on server configuration unless 103`nghttp2_option_set_no_recv_client_magic()` is used with nonzero 104option value. 105 106.. _http-messaging: 107 108HTTP Messaging 109-------------- 110 111By default, nghttp2 library checks HTTP messaging rules described in 112`HTTP/2 specification, section 8 113<https://tools.ietf.org/html/rfc7540#section-8>`_. Everything 114described in that section is not validated however. We briefly 115describe what the library does in this area. In the following 116description, without loss of generality we omit CONTINUATION frame 117since they must follow HEADERS frame and are processed atomically. In 118other words, they are just one big HEADERS frame. To disable these 119validations, use `nghttp2_option_set_no_http_messaging()`. Please 120note that disabling this feature does not change the fundamental 121client and server model of HTTP. That is, even if the validation is 122disabled, only client can send requests. 123 124For HTTP request, including those carried by PUSH_PROMISE, HTTP 125message starts with one HEADERS frame containing request headers. It 126is followed by zero or more DATA frames containing request body, which 127is followed by zero or one HEADERS containing trailer headers. The 128request headers must include ":scheme", ":method" and ":path" pseudo 129header fields unless ":method" is not "CONNECT". ":authority" is 130optional, but nghttp2 requires either ":authority" or "Host" header 131field must be present. If ":method" is "CONNECT", the request headers 132must include ":method" and ":authority" and must omit ":scheme" and 133":path". 134 135For HTTP response, HTTP message starts with zero or more HEADERS 136frames containing non-final response (status code 1xx). They are 137followed by one HEADERS frame containing final response headers 138(non-1xx). It is followed by zero or more DATA frames containing 139response body, which is followed by zero or one HEADERS containing 140trailer headers. The non-final and final response headers must 141contain ":status" pseudo header field containing 3 digits only. 142 143All request and response headers must include exactly one valid value 144for each pseudo header field. Additionally nghttp2 requires all 145request headers must not include more than one "Host" header field. 146 147HTTP/2 prohibits connection-specific header fields. The following 148header fields must not appear: "Connection", "Keep-Alive", 149"Proxy-Connection", "Transfer-Encoding" and "Upgrade". Additionally, 150"TE" header field must not include any value other than "trailers". 151 152Each header field name and value must obey the field-name and 153field-value production rules described in `RFC 7230, section 1543.2. <https://tools.ietf.org/html/rfc7230#section-3.2>`_. 155Additionally, all field name must be lower cased. The invalid header 156fields are treated as stream error, and that stream is reset. If 157application wants to treat these headers in their own way, use 158`nghttp2_on_invalid_header_callback 159<https://nghttp2.org/documentation/types.html#c.nghttp2_on_invalid_header_callback>`_. 160 161For "http" or "https" URIs, ":path" pseudo header fields must start 162with "/". The only exception is OPTIONS request, in that case, "*" is 163allowed in ":path" pseudo header field to represent system-wide 164OPTIONS request. 165 166With the above validations, nghttp2 library guarantees that header 167field name passed to `nghttp2_on_header_callback()` is not empty. 168Also required pseudo headers are all present and not empty. 169 170nghttp2 enforces "Content-Length" validation as well. All request or 171response headers must not contain more than one "Content-Length" 172header field. If "Content-Length" header field is present, it must be 173parsed as 64 bit signed integer. The sum of data length in the 174following DATA frames must match with the number in "Content-Length" 175header field if it is present (this does not include padding bytes). 176 177RFC 7230 says that server must not send "Content-Length" in any 178response with 1xx, and 204 status code. It also says that 179"Content-Length" is not allowed in any response with 200 status code 180to a CONNECT request. nghttp2 enforces them as well. 181 182Any deviation results in stream error of type PROTOCOL_ERROR. If 183error is found in PUSH_PROMISE frame, stream error is raised against 184promised stream. 185 186The order of transmission of the HTTP/2 frames 187---------------------------------------------- 188 189This section describes the internals of libnghttp2 about the 190scheduling of transmission of HTTP/2 frames. This is pretty much 191internal stuff, so the details could change in the future versions of 192the library. 193 194libnghttp2 categorizes HTTP/2 frames into 4 categories: urgent, 195regular, syn_stream, and data in the order of higher priority. 196 197The urgent category includes PING and SETTINGS. They are sent with 198highest priority. The order inside the category is FIFO. 199 200The regular category includes frames other than PING, SETTINGS, DATA, 201and HEADERS which does not create stream (which counts toward 202concurrent stream limit). The order inside the category is FIFO. 203 204The syn_stream category includes HEADERS frame which creates stream, 205that counts toward the concurrent stream limit. 206 207The data category includes DATA frame, and the scheduling among DATA 208frames are determined by HTTP/2 dependency tree. 209 210If the application wants to send frames in the specific order, and the 211default transmission order does not fit, it has to schedule frames by 212itself using the callbacks (e.g., 213:type:`nghttp2_on_frame_send_callback`). 214 215RST_STREAM has special side effect when it is submitted by 216`nghttp2_submit_rst_stream()`. It cancels all pending HEADERS and 217DATA frames whose stream ID matches the one in the RST_STREAM frame. 218This may cause unexpected behaviour for the application in some cases. 219For example, suppose that application wants to send RST_STREAM after 220sending response HEADERS and DATA. Because of the reason we mentioned 221above, the following code does not work: 222 223.. code-block:: c 224 225 nghttp2_submit_response(...) 226 nghttp2_submit_rst_stream(...) 227 228RST_STREAM cancels HEADERS (and DATA), and just RST_STREAM is sent. 229The correct way is use :type:`nghttp2_on_frame_send_callback`, and 230after HEADERS and DATA frames are sent, issue 231`nghttp2_submit_rst_stream()`. FYI, 232:type:`nghttp2_on_frame_not_send_callback` tells you why frames are 233not sent. 234 235Implement user defined HTTP/2 non-critical extensions 236----------------------------------------------------- 237 238As of nghttp2 v1.8.0, we have added HTTP/2 non-critical extension 239framework, which lets application send and receive user defined custom 240HTTP/2 non-critical extension frames. nghttp2 also offers built-in 241functionality to send and receive official HTTP/2 extension frames 242(e.g., ALTSVC frame). For these built-in handler, refer to the next 243section. 244 245To send extension frame, use `nghttp2_submit_extension()`, and 246implement :type:`nghttp2_pack_extension_callback`. The callback 247implements how to encode data into wire format. The callback must be 248set to :type:`nghttp2_session_callbacks` using 249`nghttp2_session_callbacks_set_pack_extension_callback()`. 250 251For example, we will illustrate how to send `ALTSVC 252<https://tools.ietf.org/html/rfc7838>`_ frame. 253 254.. code-block:: c 255 256 typedef struct { 257 const char *origin; 258 const char *field; 259 } alt_svc; 260 261 ssize_t pack_extension_callback(nghttp2_session *session, uint8_t *buf, 262 size_t len, const nghttp2_frame *frame, 263 void *user_data) { 264 const alt_svc *altsvc = (const alt_svc *)frame->ext.payload; 265 size_t originlen = strlen(altsvc->origin); 266 size_t fieldlen = strlen(altsvc->field); 267 268 uint8_t *p; 269 270 if (len < 2 + originlen + fieldlen || originlen > 0xffff) { 271 return NGHTTP2_ERR_CANCEL; 272 } 273 274 p = buf; 275 *p++ = originlen >> 8; 276 *p++ = originlen & 0xff; 277 memcpy(p, altsvc->origin, originlen); 278 p += originlen; 279 memcpy(p, altsvc->field, fieldlen); 280 p += fieldlen; 281 282 return p - buf; 283 } 284 285This implements :type:`nghttp2_pack_extension_callback`. We have to 286set this callback to :type:`nghttp2_session_callbacks`: 287 288.. code-block:: c 289 290 nghttp2_session_callbacks_set_pack_extension_callback( 291 callbacks, pack_extension_callback); 292 293To send ALTSVC frame, call `nghttp2_submit_extension()`: 294 295.. code-block:: c 296 297 static const alt_svc altsvc = {"example.com", "h2=\":8000\""}; 298 299 nghttp2_submit_extension(session, 0xa, NGHTTP2_FLAG_NONE, 0, 300 (void *)&altsvc); 301 302Notice that ALTSVC is use frame type ``0xa``. 303 304To receive extension frames, implement 2 callbacks: 305:type:`nghttp2_unpack_extension_callback` and 306:type:`nghttp2_on_extension_chunk_recv_callback`. 307:type:`nghttp2_unpack_extension_callback` implements the way how to 308decode wire format. :type:`nghttp2_on_extension_chunk_recv_callback` 309implements how to buffer the incoming extension payload. These 310callbacks must be set using 311`nghttp2_session_callbacks_set_unpack_extension_callback()` and 312`nghttp2_session_callbacks_set_on_extension_chunk_recv_callback()` 313respectively. The application also must tell the library which 314extension frame type it is willing to receive using 315`nghttp2_option_set_user_recv_extension_type()`. Note that the 316application has to create :type:`nghttp2_option` object for that 317purpose, and initialize session with it. 318 319We use ALTSVC again to illustrate how to receive extension frames. We 320use different ``alt_svc`` struct than the previous one. 321 322First implement 2 callbacks. We store incoming ALTSVC payload to 323global variable ``altsvc_buffer``. Don't do this in production code 324since this is not thread safe: 325 326.. code-block:: c 327 328 typedef struct { 329 const uint8_t *origin; 330 size_t originlen; 331 const uint8_t *field; 332 size_t fieldlen; 333 } alt_svc; 334 335 /* buffers incoming ALTSVC payload */ 336 uint8_t altsvc_buffer[4096]; 337 /* The length of byte written to altsvc_buffer */ 338 size_t altsvc_bufferlen = 0; 339 340 int on_extension_chunk_recv_callback(nghttp2_session *session, 341 const nghttp2_frame_hd *hd, 342 const uint8_t *data, size_t len, 343 void *user_data) { 344 if (sizeof(altsvc_buffer) < altsvc_bufferlen + len) { 345 altsvc_bufferlen = 0; 346 return NGHTTP2_ERR_CANCEL; 347 } 348 349 memcpy(altsvc_buffer + altsvc_bufferlen, data, len); 350 altsvc_bufferlen += len; 351 352 return 0; 353 } 354 355 int unpack_extension_callback(nghttp2_session *session, void **payload, 356 const nghttp2_frame_hd *hd, void *user_data) { 357 uint8_t *origin, *field; 358 size_t originlen, fieldlen; 359 uint8_t *p, *end; 360 alt_svc *altsvc; 361 362 if (altsvc_bufferlen < 2) { 363 altsvc_bufferlen = 0; 364 return NGHTTP2_ERR_CANCEL; 365 } 366 367 p = altsvc_buffer; 368 end = altsvc_buffer + altsvc_bufferlen; 369 370 originlen = ((*p) << 8) + *(p + 1); 371 p += 2; 372 373 if (p + originlen > end) { 374 altsvc_bufferlen = 0; 375 return NGHTTP2_ERR_CANCEL; 376 } 377 378 origin = p; 379 field = p + originlen; 380 fieldlen = end - field; 381 382 altsvc = (alt_svc *)malloc(sizeof(alt_svc)); 383 altsvc->origin = origin; 384 altsvc->originlen = originlen; 385 altsvc->field = field; 386 altsvc->fieldlen = fieldlen; 387 388 *payload = altsvc; 389 390 altsvc_bufferlen = 0; 391 392 return 0; 393 } 394 395Set these callbacks to :type:`nghttp2_session_callbacks`: 396 397.. code-block:: c 398 399 nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( 400 callbacks, on_extension_chunk_recv_callback); 401 402 nghttp2_session_callbacks_set_unpack_extension_callback( 403 callbacks, unpack_extension_callback); 404 405 406In ``unpack_extension_callback`` above, we set unpacked ``alt_svc`` 407object to ``*payload``. nghttp2 library then, calls 408:type:`nghttp2_on_frame_recv_callback`, and ``*payload`` will be 409available as ``frame->ext.payload``: 410 411.. code-block:: c 412 413 int on_frame_recv_callback(nghttp2_session *session, 414 const nghttp2_frame *frame, void *user_data) { 415 416 switch (frame->hd.type) { 417 ... 418 case 0xa: { 419 alt_svc *altsvc = (alt_svc *)frame->ext.payload; 420 fprintf(stderr, "ALTSVC frame received\n"); 421 fprintf(stderr, " origin: %.*s\n", (int)altsvc->originlen, altsvc->origin); 422 fprintf(stderr, " field : %.*s\n", (int)altsvc->fieldlen, altsvc->field); 423 free(altsvc); 424 break; 425 } 426 } 427 428 return 0; 429 } 430 431Finally, application should set the extension frame types it is 432willing to receive: 433 434.. code-block:: c 435 436 nghttp2_option_set_user_recv_extension_type(option, 0xa); 437 438The :type:`nghttp2_option` must be set to :type:`nghttp2_session` on 439its creation: 440 441.. code-block:: c 442 443 nghttp2_session_client_new2(&session, callbacks, user_data, option); 444 445How to use built-in HTTP/2 extension frame handlers 446--------------------------------------------------- 447 448In the previous section, we talked about the user defined HTTP/2 449extension frames. In this section, we talk about HTTP/2 extension 450frame support built into nghttp2 library. 451 452As of this writing, nghttp2 supports ALTSVC extension frame. To send 453ALTSVC frame, use `nghttp2_submit_altsvc()` function. 454 455To receive ALTSVC frame through built-in functionality, application 456has to use `nghttp2_option_set_builtin_recv_extension_type()` to 457indicate the willingness of receiving ALTSVC frame: 458 459.. code-block:: c 460 461 nghttp2_option_set_builtin_recv_extension_type(option, NGHTTP2_ALTSVC); 462 463This is very similar to the case when we used to receive user defined 464frames. 465 466If the same frame type is set using 467`nghttp2_option_set_builtin_recv_extension_type()` and 468`nghttp2_option_set_user_recv_extension_type()`, the latter takes 469precedence. Application can implement its own frame handler rather 470than using built-in handler. 471 472The :type:`nghttp2_option` must be set to :type:`nghttp2_session` on 473its creation, like so: 474 475.. code-block:: c 476 477 nghttp2_session_client_new2(&session, callbacks, user_data, option); 478 479When ALTSVC is received, :type:`nghttp2_on_frame_recv_callback` will 480be called as usual. 481 482Stream priorities 483----------------- 484 485By default, the stream prioritization scheme described in :rfc:`7540` 486is used. This scheme has been formally deprecated by :rfc:`9113`. In 487order to disable it, send 488:enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` of 489value of 1 via `nghttp2_submit_settings()`. This settings ID is 490defined by :rfc:`9218`. The sender of this settings value disables 491RFC 7540 priorities, and instead it enables RFC 9218 Extensible 492Prioritization Scheme. This new prioritization scheme has 2 methods 493to convey the stream priorities to a remote endpoint: Priority header 494field and PRIORITY_UPDATE frame. nghttp2 supports both methods. In 495order to receive and process PRIORITY_UPDATE frame, server has to call 496``nghttp2_option_set_builtin_recv_extension_type(option, 497NGHTTP2_PRIORITY_UPDATE)`` (see the above section), and pass the 498option to `nghttp2_session_server_new2()` or 499`nghttp2_session_server_new3()` to create a server session. Client 500can send Priority header field via `nghttp2_submit_request()`. It can 501also send PRIORITY_UPDATE frame via 502`nghttp2_submit_priority_update()`. Server processes Priority header 503field in a request header field and updates the stream priority unless 504HTTP messaging rule enforcement is disabled (see 505`nghttp2_option_set_no_http_messaging()`). 506 507For the purpose of smooth migration from RFC 7540 priorities, client 508is advised to send 509:enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` of 510value of 1. Until it receives the first server SETTINGS frame, it can 511send both RFC 7540 and RFC 9128 priority signals. If client receives 512SETTINGS_NO_RFC7540_PRIORITIES of value of 0, or it is omitted , 513client stops sending PRIORITY_UPDATE frame. Priority header field 514will be sent in anyway since it is an end-to-end signal. If 515SETTINGS_NO_RFC7540_PRIORITIES of value of 1 is received, client stops 516sending RFC 7540 priority signals. This is the advice described in 517:rfc:`9218#section-2.1.1`. 518 519Server has an optional mechanism to fallback to RFC 7540 priorities. 520By default, if server sends SETTINGS_NO_RFC7540_PRIORITIES of value of 5211, it completely disables RFC 7540 priorities and no fallback. By 522setting nonzero value to 523`nghttp2_option_set_server_fallback_rfc7540_priorities()`, server 524falls back to RFC 7540 priorities if it sends 525SETTINGS_NO_RFC7540_PRIORITIES value of value of 1, and client omits 526SETTINGS_NO_RFC7540_PRIORITIES in its SETTINGS frame. 527