summaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--doc/.gitignore19
-rw-r--r--doc/CMakeLists.txt352
-rw-r--r--doc/Makefile.am366
-rw-r--r--doc/README.rst160
-rw-r--r--doc/_exts/rubydomain/LICENSE.rubydomain28
-rw-r--r--doc/_exts/rubydomain/__init__.py14
-rw-r--r--doc/_exts/rubydomain/rubydomain.py703
-rw-r--r--doc/bash_completion/h2load19
-rwxr-xr-xdoc/bash_completion/make_bash_completion.py75
-rw-r--r--doc/bash_completion/nghttp19
-rw-r--r--doc/bash_completion/nghttpd19
-rw-r--r--doc/bash_completion/nghttpx19
-rw-r--r--doc/building-android-binary.rst.in1
-rw-r--r--doc/conf.py.in252
-rw-r--r--doc/contribute.rst.in1
-rw-r--r--doc/docutils.conf2
-rw-r--r--doc/h2load-howto.rst.in1
-rw-r--r--doc/h2load.1530
-rw-r--r--doc/h2load.1.rst434
-rw-r--r--doc/h2load.h2r120
-rw-r--r--doc/index.rst.in1
-rw-r--r--doc/make.bat170
-rwxr-xr-xdoc/mkapiref.py343
-rw-r--r--doc/nghttp.1336
-rw-r--r--doc/nghttp.1.rst276
-rw-r--r--doc/nghttp.h2r57
-rw-r--r--doc/nghttp2.h.rst.in4
-rw-r--r--doc/nghttp2ver.h.rst.in4
-rw-r--r--doc/nghttpd.1236
-rw-r--r--doc/nghttpd.1.rst186
-rw-r--r--doc/nghttpd.h2r4
-rw-r--r--doc/nghttpx-howto.rst.in1
-rw-r--r--doc/nghttpx.12770
-rw-r--r--doc/nghttpx.1.rst2526
-rw-r--r--doc/nghttpx.h2r719
-rw-r--r--doc/package_README.rst.in1
-rw-r--r--doc/programmers-guide.rst526
-rw-r--r--doc/security.rst1
-rw-r--r--doc/sources/building-android-binary.rst127
-rw-r--r--doc/sources/contribute.rst56
-rw-r--r--doc/sources/h2load-howto.rst142
-rw-r--r--doc/sources/index.rst50
-rw-r--r--doc/sources/nghttpx-howto.rst642
-rw-r--r--doc/sources/security.rst33
-rw-r--r--doc/sources/tutorial-client.rst464
-rw-r--r--doc/sources/tutorial-hpack.rst126
-rw-r--r--doc/sources/tutorial-server.rst577
-rw-r--r--doc/tutorial-client.rst.in6
-rw-r--r--doc/tutorial-hpack.rst.in6
-rw-r--r--doc/tutorial-server.rst.in6
-rw-r--r--docker/Dockerfile78
-rw-r--r--docker/README.rst25
52 files changed, 13633 insertions, 0 deletions
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 0000000..ed9e634
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,19 @@
+# generated files
+apiref.rst
+building-android-binary.rst
+conf.py
+contribute.rst
+enums.rst
+h2load-howto.rst
+index.rst
+macros.rst
+manual/
+nghttp2.h.rst
+nghttp2_*.rst
+nghttp2ver.h.rst
+nghttpx-howto.rst
+package_README.rst
+tutorial-client.rst
+tutorial-hpack.rst
+tutorial-server.rst
+types.rst
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..531791f
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,352 @@
+# Generated documents
+set(APIDOCS
+ macros.rst
+ enums.rst
+ types.rst
+ nghttp2_check_header_name.rst
+ nghttp2_check_header_value.rst
+ nghttp2_hd_deflate_bound.rst
+ nghttp2_hd_deflate_change_table_size.rst
+ nghttp2_hd_deflate_del.rst
+ nghttp2_hd_deflate_get_dynamic_table_size.rst
+ nghttp2_hd_deflate_get_max_dynamic_table_size.rst
+ nghttp2_hd_deflate_get_num_table_entries.rst
+ nghttp2_hd_deflate_get_table_entry.rst
+ nghttp2_hd_deflate_hd.rst
+ nghttp2_hd_deflate_hd_vec.rst
+ nghttp2_hd_deflate_new.rst
+ nghttp2_hd_deflate_new2.rst
+ nghttp2_hd_inflate_change_table_size.rst
+ nghttp2_hd_inflate_del.rst
+ nghttp2_hd_inflate_end_headers.rst
+ nghttp2_hd_inflate_get_dynamic_table_size.rst
+ nghttp2_hd_inflate_get_max_dynamic_table_size.rst
+ nghttp2_hd_inflate_get_num_table_entries.rst
+ nghttp2_hd_inflate_get_table_entry.rst
+ nghttp2_hd_inflate_hd.rst
+ nghttp2_hd_inflate_hd2.rst
+ nghttp2_hd_inflate_new.rst
+ nghttp2_hd_inflate_new2.rst
+ nghttp2_http2_strerror.rst
+ nghttp2_is_fatal.rst
+ nghttp2_nv_compare_name.rst
+ nghttp2_option_del.rst
+ nghttp2_option_new.rst
+ nghttp2_option_set_builtin_recv_extension_type.rst
+ nghttp2_option_set_max_deflate_dynamic_table_size.rst
+ nghttp2_option_set_max_reserved_remote_streams.rst
+ nghttp2_option_set_max_send_header_block_length.rst
+ nghttp2_option_set_no_auto_ping_ack.rst
+ nghttp2_option_set_no_auto_window_update.rst
+ nghttp2_option_set_no_http_messaging.rst
+ nghttp2_option_set_no_recv_client_magic.rst
+ nghttp2_option_set_peer_max_concurrent_streams.rst
+ nghttp2_option_set_user_recv_extension_type.rst
+ nghttp2_option_set_max_settings.rst
+ nghttp2_pack_settings_payload.rst
+ nghttp2_priority_spec_check_default.rst
+ nghttp2_priority_spec_default_init.rst
+ nghttp2_priority_spec_init.rst
+ nghttp2_rcbuf_decref.rst
+ nghttp2_rcbuf_get_buf.rst
+ nghttp2_rcbuf_incref.rst
+ nghttp2_rcbuf_is_static.rst
+ nghttp2_select_next_protocol.rst
+ nghttp2_session_callbacks_del.rst
+ nghttp2_session_callbacks_new.rst
+ nghttp2_session_callbacks_set_before_frame_send_callback.rst
+ nghttp2_session_callbacks_set_data_source_read_length_callback.rst
+ nghttp2_session_callbacks_set_error_callback.rst
+ nghttp2_session_callbacks_set_on_begin_frame_callback.rst
+ nghttp2_session_callbacks_set_on_begin_headers_callback.rst
+ nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst
+ nghttp2_session_callbacks_set_on_extension_chunk_recv_callback.rst
+ nghttp2_session_callbacks_set_on_frame_not_send_callback.rst
+ nghttp2_session_callbacks_set_on_frame_recv_callback.rst
+ nghttp2_session_callbacks_set_on_frame_send_callback.rst
+ nghttp2_session_callbacks_set_on_header_callback.rst
+ nghttp2_session_callbacks_set_on_header_callback2.rst
+ nghttp2_session_callbacks_set_on_invalid_frame_recv_callback.rst
+ nghttp2_session_callbacks_set_on_invalid_header_callback.rst
+ nghttp2_session_callbacks_set_on_invalid_header_callback2.rst
+ nghttp2_session_callbacks_set_on_stream_close_callback.rst
+ nghttp2_session_callbacks_set_pack_extension_callback.rst
+ nghttp2_session_callbacks_set_recv_callback.rst
+ nghttp2_session_callbacks_set_select_padding_callback.rst
+ nghttp2_session_callbacks_set_send_callback.rst
+ nghttp2_session_callbacks_set_send_data_callback.rst
+ nghttp2_session_callbacks_set_unpack_extension_callback.rst
+ nghttp2_session_change_stream_priority.rst
+ nghttp2_session_check_request_allowed.rst
+ nghttp2_session_check_server_session.rst
+ nghttp2_session_client_new.rst
+ nghttp2_session_client_new2.rst
+ nghttp2_session_client_new3.rst
+ nghttp2_session_consume.rst
+ nghttp2_session_consume_connection.rst
+ nghttp2_session_consume_stream.rst
+ nghttp2_session_create_idle_stream.rst
+ nghttp2_session_del.rst
+ nghttp2_session_find_stream.rst
+ nghttp2_session_get_effective_local_window_size.rst
+ nghttp2_session_get_effective_recv_data_length.rst
+ nghttp2_session_get_hd_deflate_dynamic_table_size.rst
+ nghttp2_session_get_hd_inflate_dynamic_table_size.rst
+ nghttp2_session_get_last_proc_stream_id.rst
+ nghttp2_session_get_local_settings.rst
+ nghttp2_session_get_local_window_size.rst
+ nghttp2_session_get_next_stream_id.rst
+ nghttp2_session_get_outbound_queue_size.rst
+ nghttp2_session_get_remote_settings.rst
+ nghttp2_session_get_remote_window_size.rst
+ nghttp2_session_get_root_stream.rst
+ nghttp2_session_get_stream_effective_local_window_size.rst
+ nghttp2_session_get_stream_effective_recv_data_length.rst
+ nghttp2_session_get_stream_local_close.rst
+ nghttp2_session_get_stream_local_window_size.rst
+ nghttp2_session_get_stream_remote_close.rst
+ nghttp2_session_get_stream_remote_window_size.rst
+ nghttp2_session_get_stream_user_data.rst
+ nghttp2_session_mem_recv.rst
+ nghttp2_session_mem_send.rst
+ nghttp2_session_recv.rst
+ nghttp2_session_resume_data.rst
+ nghttp2_session_send.rst
+ nghttp2_session_server_new.rst
+ nghttp2_session_server_new2.rst
+ nghttp2_session_server_new3.rst
+ nghttp2_session_set_local_window_size.rst
+ nghttp2_session_set_next_stream_id.rst
+ nghttp2_session_set_stream_user_data.rst
+ nghttp2_session_terminate_session.rst
+ nghttp2_session_terminate_session2.rst
+ nghttp2_session_upgrade.rst
+ nghttp2_session_upgrade2.rst
+ nghttp2_session_want_read.rst
+ nghttp2_session_want_write.rst
+ nghttp2_set_debug_vprintf_callback.rst
+ nghttp2_stream_get_first_child.rst
+ nghttp2_stream_get_next_sibling.rst
+ nghttp2_stream_get_parent.rst
+ nghttp2_stream_get_previous_sibling.rst
+ nghttp2_stream_get_state.rst
+ nghttp2_stream_get_sum_dependency_weight.rst
+ nghttp2_stream_get_weight.rst
+ nghttp2_strerror.rst
+ nghttp2_submit_altsvc.rst
+ nghttp2_submit_data.rst
+ nghttp2_submit_extension.rst
+ nghttp2_submit_goaway.rst
+ nghttp2_submit_headers.rst
+ nghttp2_submit_ping.rst
+ nghttp2_submit_priority.rst
+ nghttp2_submit_push_promise.rst
+ nghttp2_submit_request.rst
+ nghttp2_submit_response.rst
+ nghttp2_submit_rst_stream.rst
+ nghttp2_submit_settings.rst
+ nghttp2_submit_shutdown_notice.rst
+ nghttp2_submit_trailer.rst
+ nghttp2_submit_window_update.rst
+ nghttp2_version.rst
+)
+
+set(MAN_PAGES
+ nghttp.1
+ nghttpd.1
+ nghttpx.1
+ h2load.1
+)
+
+# Other .rst files from the source tree that need to be copied
+# XXX move them to sources/ and create .in files?
+set(RST_FILES
+ README.rst
+ programmers-guide.rst
+ nghttp.1.rst
+ nghttpd.1.rst
+ nghttpx.1.rst
+ h2load.1.rst
+)
+
+# XXX unused for now
+set(EXTRA_DIST
+ mkapiref.py
+ ${RST_FILES}
+ ${APIDOCS}
+ sources/index.rst
+ sources/tutorial-client.rst
+ sources/tutorial-server.rst
+ sources/tutorial-hpack.rst
+ sources/nghttpx-howto.rst
+ sources/h2load-howto.rst
+ sources/building-android-binary.rst
+ sources/contribute.rst
+ _exts/rubydomain/LICENSE.rubydomain
+ _exts/rubydomain/__init__.py
+ _exts/rubydomain/rubydomain.py
+ _themes/sphinx_rtd_theme/__init__.py
+ _themes/sphinx_rtd_theme/breadcrumbs.html
+ _themes/sphinx_rtd_theme/footer.html
+ _themes/sphinx_rtd_theme/layout.html
+ _themes/sphinx_rtd_theme/layout_old.html
+ _themes/sphinx_rtd_theme/search.html
+ _themes/sphinx_rtd_theme/searchbox.html
+ _themes/sphinx_rtd_theme/static/css/badge_only.css
+ _themes/sphinx_rtd_theme/static/css/theme.css
+ _themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf
+ _themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot
+ _themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg
+ _themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf
+ _themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff
+ _themes/sphinx_rtd_theme/static/js/theme.js
+ _themes/sphinx_rtd_theme/theme.conf
+ _themes/sphinx_rtd_theme/versions.html
+ ${MAN_PAGES}
+ bash_completion/nghttp
+ bash_completion/nghttpd
+ bash_completion/nghttpx
+ bash_completion/h2load
+)
+
+# Based on Makefile for Sphinx documentation
+
+# You can set these variables from the command line.
+set(SPHINXOPTS)
+set(SPHINXBUILD sphinx-build)
+set(PAPER)
+set(BUILDDIR manual)
+
+# Internal variables.
+set(PAPEROPT_a4 -D latex_paper_size=a4)
+set(PAPEROPT_letter -D latex_paper_size=letter)
+set(ALLSPHINXOPTS -d ${BUILDDIR}/doctrees ${PAPEROPT_${PAPER}} ${SPHINXOPTS} .)
+
+# "Please use `make <target>' where <target> is one of"
+# " html to make standalone HTML files"
+# " dirhtml to make HTML files named index.html in directories"
+# " singlehtml to make a single large HTML file"
+# " pickle to make pickle files"
+# " json to make JSON files"
+# " htmlhelp to make HTML files and a HTML help project"
+# " qthelp to make HTML files and a qthelp project"
+# " devhelp to make HTML files and a Devhelp project"
+# " epub to make an epub"
+# " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+# " latexpdf to make LaTeX files and run them through pdflatex"
+# " text to make text files"
+# " man to make manual pages"
+# " changes to make an overview of all changed/added/deprecated items"
+# " linkcheck to check all external links for integrity"
+# " doctest to run all doctests embedded in the documentation (if enabled)"
+
+
+# Copy files for out-of-tree builds
+if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
+ set(RST_BUILD_FILES)
+ foreach(rstfile IN LISTS RST_FILES)
+ set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${rstfile}")
+ add_custom_command(OUTPUT "${outfile}"
+ COMMAND ${CMAKE_COMMAND} -E copy
+ "${CMAKE_CURRENT_SOURCE_DIR}/${rstfile}" "${outfile}"
+ DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${rstfile}"
+ )
+ list(APPEND RST_BUILD_FILES "${outfile}")
+ endforeach()
+else()
+ set(RST_BUILD_FILES "${RST_FILES}")
+endif()
+
+set(apiref_SOURCES
+ ${CMAKE_BINARY_DIR}/lib/includes/nghttp2/nghttp2ver.h
+ ${CMAKE_SOURCE_DIR}/lib/includes/nghttp2/nghttp2.h
+)
+# Generates apiref.rst and other files
+add_custom_command(
+ OUTPUT
+ apiref.rst
+ ${APIDOCS}
+ COMMAND
+ "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkapiref.py"
+ apiref.rst macros.rst enums.rst types.rst .
+ ${apiref_SOURCES}
+ DEPENDS
+ ${RST_BUILD_FILES}
+ ${apiref_SOURCES}
+)
+
+
+
+set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${BUILDDIR}")
+
+# Invokes sphinx-build and prints the given messages when completed
+function(sphinxbuild builder)
+ set(echo_commands)
+ foreach(message IN LISTS ARGN)
+ list(APPEND echo_commands COMMAND ${CMAKE_COMMAND} -E echo "${message}")
+ endforeach()
+ add_custom_target(${builder}
+ COMMAND "${SPHINXBUILD}" -b ${builder} ${ALLSPHINXOPTS} "${BUILDDIR}/${builder}"
+ COMMAND ${CMAKE_COMMAND} -E echo
+ ${echo_commands}
+ VERBATIM
+ DEPENDS apiref.rst
+ )
+endfunction()
+
+foreach(builder html dirhtml singlehtml)
+ sphinxbuild(${builder}
+ "Build finished. The HTML pages are in ${BUILDDIR}/${builder}.")
+endforeach()
+sphinxbuild(pickle "Build finished; now you can process the pickle files.")
+sphinxbuild(json "Build finished; now you can process the JSON files.")
+sphinxbuild(htmlhelp
+ "Build finished; now you can run HTML Help Workshop with the"
+ ".hhp project file in ${BUILDDIR}/htmlhelp."
+)
+sphinxbuild(qthelp
+ "Build finished; now you can run \"qcollectiongenerator\" with the"
+ ".qhcp project file in ${BUILDDIR}/qthelp, like this:"
+ "# qcollectiongenerator ${BUILDDIR}/qthelp/nghttp2.qhcp"
+ "To view the help file:"
+ "# assistant -collectionFile ${BUILDDIR}/qthelp/nghttp2.qhc"
+)
+sphinxbuild(devhelp
+ "Build finished."
+ "To view the help file:"
+ "# mkdir -p ~/.local/share/devhelp/nghttp2"
+ "# ln -s ${BUILDDIR}/devhelp ~/.local/share/devhelp/nghttp2"
+ "# devhelp"
+)
+sphinxbuild(epub "Build finished. The epub file is in ${BUILDDIR}/epub.")
+sphinxbuild(latex
+ "Build finished; the LaTeX files are in ${BUILDDIR}/latex."
+ "Run `make' in that directory to run these through (pdf)latex"
+ "(use `make latexpdf' here to do that automatically)."
+)
+
+# Invoke the Makefile generated by sphinx
+add_custom_target(latexpdf
+ COMMAND ${CMAKE_COMMAND} -E echo "Running LaTeX files through pdflatex..."
+ COMMAND make -C "${BUILDDIR}/latex" all-pdf
+ COMMAND ${CMAKE_COMMAND} -E echo "pdflatex finished; the PDF files are in ${BUILDDIR}/latex."
+ DEPENDS latex
+)
+
+sphinxbuild(text "Build finished. The text files are in ${BUILDDIR}/text.")
+sphinxbuild(man "Build finished. The manual pages are in ${BUILDDIR}/man.")
+sphinxbuild(changes "The overview file is in ${BUILDDIR}/changes.")
+sphinxbuild(linkcheck
+ "Link check complete; look for any errors in the above output"
+ "or in ${BUILDDIR}/linkcheck/output.txt."
+)
+sphinxbuild(doctest
+ "Testing of doctests in the sources finished, look at the"
+ "results in ${BUILDDIR}/doctest/output.txt."
+)
+
+foreach(_man_page IN LISTS MAN_PAGES)
+ install(FILES ${_man_page}
+ DESTINATION "${CMAKE_INSTALL_MANDIR}/man1"
+ )
+endforeach()
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..7d7f31c
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,366 @@
+# nghttp2 - HTTP/2 C Library
+
+# Copyright (c) 2012 Tatsuhiro Tsujikawa
+
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+man_MANS = nghttp.1 nghttpd.1 nghttpx.1 h2load.1
+
+APIDOCS= \
+ macros.rst \
+ enums.rst \
+ types.rst \
+ nghttp2_check_authority.rst \
+ nghttp2_check_header_name.rst \
+ nghttp2_check_header_value.rst \
+ nghttp2_check_header_value_rfc9113.rst \
+ nghttp2_check_method.rst \
+ nghttp2_check_path.rst \
+ nghttp2_extpri_parse_priority.rst \
+ nghttp2_hd_deflate_bound.rst \
+ nghttp2_hd_deflate_change_table_size.rst \
+ nghttp2_hd_deflate_del.rst \
+ nghttp2_hd_deflate_get_dynamic_table_size.rst \
+ nghttp2_hd_deflate_get_max_dynamic_table_size.rst \
+ nghttp2_hd_deflate_get_num_table_entries.rst \
+ nghttp2_hd_deflate_get_table_entry.rst \
+ nghttp2_hd_deflate_hd.rst \
+ nghttp2_hd_deflate_hd_vec.rst \
+ nghttp2_hd_deflate_new.rst \
+ nghttp2_hd_deflate_new2.rst \
+ nghttp2_hd_inflate_change_table_size.rst \
+ nghttp2_hd_inflate_del.rst \
+ nghttp2_hd_inflate_end_headers.rst \
+ nghttp2_hd_inflate_get_dynamic_table_size.rst \
+ nghttp2_hd_inflate_get_max_dynamic_table_size.rst \
+ nghttp2_hd_inflate_get_num_table_entries.rst \
+ nghttp2_hd_inflate_get_table_entry.rst \
+ nghttp2_hd_inflate_hd.rst \
+ nghttp2_hd_inflate_hd2.rst \
+ nghttp2_hd_inflate_new.rst \
+ nghttp2_hd_inflate_new2.rst \
+ nghttp2_http2_strerror.rst \
+ nghttp2_is_fatal.rst \
+ nghttp2_nv_compare_name.rst \
+ nghttp2_option_del.rst \
+ nghttp2_option_new.rst \
+ nghttp2_option_set_builtin_recv_extension_type.rst \
+ nghttp2_option_set_max_deflate_dynamic_table_size.rst \
+ nghttp2_option_set_max_reserved_remote_streams.rst \
+ nghttp2_option_set_max_send_header_block_length.rst \
+ nghttp2_option_set_no_auto_ping_ack.rst \
+ nghttp2_option_set_no_auto_window_update.rst \
+ nghttp2_option_set_no_closed_streams.rst \
+ nghttp2_option_set_no_http_messaging.rst \
+ nghttp2_option_set_no_recv_client_magic.rst \
+ nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation.rst \
+ nghttp2_option_set_peer_max_concurrent_streams.rst \
+ nghttp2_option_set_server_fallback_rfc7540_priorities.rst \
+ nghttp2_option_set_user_recv_extension_type.rst \
+ nghttp2_option_set_max_outbound_ack.rst \
+ nghttp2_option_set_max_settings.rst \
+ nghttp2_option_set_stream_reset_rate_limit.rst \
+ nghttp2_pack_settings_payload.rst \
+ nghttp2_priority_spec_check_default.rst \
+ nghttp2_priority_spec_default_init.rst \
+ nghttp2_priority_spec_init.rst \
+ nghttp2_rcbuf_decref.rst \
+ nghttp2_rcbuf_get_buf.rst \
+ nghttp2_rcbuf_incref.rst \
+ nghttp2_rcbuf_is_static.rst \
+ nghttp2_select_next_protocol.rst \
+ nghttp2_select_alpn.rst \
+ nghttp2_session_callbacks_del.rst \
+ nghttp2_session_callbacks_new.rst \
+ nghttp2_session_callbacks_set_before_frame_send_callback.rst \
+ nghttp2_session_callbacks_set_data_source_read_length_callback.rst \
+ nghttp2_session_callbacks_set_error_callback.rst \
+ nghttp2_session_callbacks_set_error_callback2.rst \
+ nghttp2_session_callbacks_set_on_begin_frame_callback.rst \
+ nghttp2_session_callbacks_set_on_begin_headers_callback.rst \
+ nghttp2_session_callbacks_set_on_data_chunk_recv_callback.rst \
+ nghttp2_session_callbacks_set_on_extension_chunk_recv_callback.rst \
+ nghttp2_session_callbacks_set_on_frame_not_send_callback.rst \
+ nghttp2_session_callbacks_set_on_frame_recv_callback.rst \
+ nghttp2_session_callbacks_set_on_frame_send_callback.rst \
+ nghttp2_session_callbacks_set_on_header_callback.rst \
+ nghttp2_session_callbacks_set_on_header_callback2.rst \
+ nghttp2_session_callbacks_set_on_invalid_frame_recv_callback.rst \
+ nghttp2_session_callbacks_set_on_invalid_header_callback.rst \
+ nghttp2_session_callbacks_set_on_invalid_header_callback2.rst \
+ nghttp2_session_callbacks_set_on_stream_close_callback.rst \
+ nghttp2_session_callbacks_set_pack_extension_callback.rst \
+ nghttp2_session_callbacks_set_recv_callback.rst \
+ nghttp2_session_callbacks_set_select_padding_callback.rst \
+ nghttp2_session_callbacks_set_send_callback.rst \
+ nghttp2_session_callbacks_set_send_data_callback.rst \
+ nghttp2_session_callbacks_set_unpack_extension_callback.rst \
+ nghttp2_session_change_extpri_stream_priority.rst \
+ nghttp2_session_change_stream_priority.rst \
+ nghttp2_session_check_request_allowed.rst \
+ nghttp2_session_check_server_session.rst \
+ nghttp2_session_client_new.rst \
+ nghttp2_session_client_new2.rst \
+ nghttp2_session_client_new3.rst \
+ nghttp2_session_consume.rst \
+ nghttp2_session_consume_connection.rst \
+ nghttp2_session_consume_stream.rst \
+ nghttp2_session_create_idle_stream.rst \
+ nghttp2_session_del.rst \
+ nghttp2_session_find_stream.rst \
+ nghttp2_session_get_effective_local_window_size.rst \
+ nghttp2_session_get_effective_recv_data_length.rst \
+ nghttp2_session_get_extpri_stream_priority.rst \
+ nghttp2_session_get_hd_deflate_dynamic_table_size.rst \
+ nghttp2_session_get_hd_inflate_dynamic_table_size.rst \
+ nghttp2_session_get_last_proc_stream_id.rst \
+ nghttp2_session_get_local_settings.rst \
+ nghttp2_session_get_local_window_size.rst \
+ nghttp2_session_get_next_stream_id.rst \
+ nghttp2_session_get_outbound_queue_size.rst \
+ nghttp2_session_get_remote_settings.rst \
+ nghttp2_session_get_remote_window_size.rst \
+ nghttp2_session_get_root_stream.rst \
+ nghttp2_session_get_stream_effective_local_window_size.rst \
+ nghttp2_session_get_stream_effective_recv_data_length.rst \
+ nghttp2_session_get_stream_local_close.rst \
+ nghttp2_session_get_stream_local_window_size.rst \
+ nghttp2_session_get_stream_remote_close.rst \
+ nghttp2_session_get_stream_remote_window_size.rst \
+ nghttp2_session_get_stream_user_data.rst \
+ nghttp2_session_mem_recv.rst \
+ nghttp2_session_mem_send.rst \
+ nghttp2_session_recv.rst \
+ nghttp2_session_resume_data.rst \
+ nghttp2_session_send.rst \
+ nghttp2_session_server_new.rst \
+ nghttp2_session_server_new2.rst \
+ nghttp2_session_server_new3.rst \
+ nghttp2_session_set_local_window_size.rst \
+ nghttp2_session_set_next_stream_id.rst \
+ nghttp2_session_set_stream_user_data.rst \
+ nghttp2_session_set_user_data.rst \
+ nghttp2_session_terminate_session.rst \
+ nghttp2_session_terminate_session2.rst \
+ nghttp2_session_upgrade.rst \
+ nghttp2_session_upgrade2.rst \
+ nghttp2_session_want_read.rst \
+ nghttp2_session_want_write.rst \
+ nghttp2_set_debug_vprintf_callback.rst \
+ nghttp2_stream_get_first_child.rst \
+ nghttp2_stream_get_next_sibling.rst \
+ nghttp2_stream_get_parent.rst \
+ nghttp2_stream_get_previous_sibling.rst \
+ nghttp2_stream_get_state.rst \
+ nghttp2_stream_get_sum_dependency_weight.rst \
+ nghttp2_stream_get_weight.rst \
+ nghttp2_strerror.rst \
+ nghttp2_submit_altsvc.rst \
+ nghttp2_submit_data.rst \
+ nghttp2_submit_extension.rst \
+ nghttp2_submit_goaway.rst \
+ nghttp2_submit_headers.rst \
+ nghttp2_submit_origin.rst \
+ nghttp2_submit_ping.rst \
+ nghttp2_submit_priority.rst \
+ nghttp2_submit_priority_update.rst \
+ nghttp2_submit_push_promise.rst \
+ nghttp2_submit_request.rst \
+ nghttp2_submit_response.rst \
+ nghttp2_submit_rst_stream.rst \
+ nghttp2_submit_settings.rst \
+ nghttp2_submit_shutdown_notice.rst \
+ nghttp2_submit_trailer.rst \
+ nghttp2_submit_window_update.rst \
+ nghttp2_version.rst
+
+RST_FILES = \
+ README.rst \
+ programmers-guide.rst \
+ nghttp.1.rst \
+ nghttpd.1.rst \
+ nghttpx.1.rst \
+ h2load.1.rst
+
+EXTRA_DIST = \
+ CMakeLists.txt \
+ mkapiref.py \
+ $(RST_FILES) \
+ $(APIDOCS) \
+ sources/index.rst \
+ sources/tutorial-client.rst \
+ sources/tutorial-server.rst \
+ sources/tutorial-hpack.rst \
+ sources/nghttpx-howto.rst \
+ sources/h2load-howto.rst \
+ sources/building-android-binary.rst \
+ sources/contribute.rst \
+ sources/security.rst \
+ _exts/rubydomain/LICENSE.rubydomain \
+ _exts/rubydomain/__init__.py \
+ _exts/rubydomain/rubydomain.py \
+ $(man_MANS) \
+ bash_completion/nghttp \
+ bash_completion/nghttpd \
+ bash_completion/nghttpx \
+ bash_completion/h2load
+
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD ?= sphinx-build
+PAPER =
+BUILDDIR = manual
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+apiref.rst: \
+ $(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
+ $(top_srcdir)/lib/includes/nghttp2/nghttp2.h
+ for i in $(RST_FILES); do [ -e $(builddir)/$$i ] || cp $(srcdir)/$$i $(builddir); done
+ $(PYTHON) $(top_srcdir)/doc/mkapiref.py \
+ apiref.rst macros.rst enums.rst types.rst . $^
+
+$(APIDOCS): apiref.rst
+
+clean-local:
+ if [ $(srcdir) != $(builddir) ]; then for i in $(RST_FILES); do rm -f $(builddir)/$$i; done fi
+ -rm -f apiref.rst
+ -rm -f $(APIDOCS)
+ -rm -rf $(BUILDDIR)/*
+
+html-local: apiref.rst
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/nghttp2.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/nghttp2.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/nghttp2"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/nghttp2"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man: apiref.rst
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/doc/README.rst b/doc/README.rst
new file mode 100644
index 0000000..549e550
--- /dev/null
+++ b/doc/README.rst
@@ -0,0 +1,160 @@
+nghttp2 Documentation
+=====================
+
+The documentation of nghttp2 is generated using Sphinx. This
+directory contains the source files to be processed by Sphinx. The
+source file for API reference is generated using a script called
+``mkapiref.py`` from the nghttp2 C source code.
+
+Generating API reference
+------------------------
+
+As described earlier, we use ``mkapiref.py`` to generate rst formatted
+text of API reference from C source code. The ``mkapiref.py`` is not
+so flexible and it requires that C source code is formatted in rather
+strict rules.
+
+To generate API reference, just run ``make html``. It runs
+``mkapiref.py`` and then run Sphinx to build the entire document.
+
+The ``mkapiref.py`` reads C source code and searches the comment block
+starts with ``/**``. In other words, it only processes the comment
+block starting ``/**``. The comment block must end with ``*/``. The
+``mkapiref.py`` requires that which type of the object this comment
+block refers to. To specify the type of the object, the next line
+must contain the so-called action keyword. Currently, the following
+action keywords are supported: ``@function``, ``@functypedef``,
+``@enum``, ``@struct`` and ``@union``. The following sections
+describes each action keyword.
+
+@function
+#########
+
+``@function`` is used to refer to the function. The comment block is
+used for the document for the function. After the script sees the end
+of the comment block, it consumes the lines as the function
+declaration until the line which ends with ``;`` is encountered.
+
+In Sphinx doc, usually the function argument is formatted like
+``*this*``. But in C, ``*`` is used for dereferencing a pointer and
+we must escape ``*`` with a back slash. To avoid this, we format the
+argument like ``|this|``. The ``mkapiref.py`` translates it with
+``*this*``, as escaping ``*`` inside ``|`` and ``|`` as necessary.
+Note that this shadows the substitution feature of Sphinx.
+
+The example follows::
+
+ /**
+ * @function
+ *
+ * Submits PING frame to the |session|.
+ */
+ int nghttp2_submit_ping(nghttp2_session *session);
+
+
+@functypedef
+############
+
+``@functypedef`` is used to refer to the typedef of the function
+pointer. The formatting rule is pretty much the same with
+``@function``, but this outputs ``type`` domain, rather than
+``function`` domain.
+
+The example follows::
+
+ /**
+ * @functypedef
+ *
+ * Callback function invoked when |session| wants to send data to
+ * remote peer.
+ */
+ typedef ssize_t (*nghttp2_send_callback)
+ (nghttp2_session *session,
+ const uint8_t *data, size_t length, int flags, void *user_data);
+
+@enum
+#####
+
+``@enum`` is used to refer to the enum. Currently, only enum typedefs
+are supported. The comment block is used for the document for the
+enum type itself. To document each values, put comment block starting
+with the line ``/**`` and ending with the ``*/`` just before the enum
+value. When the line starts with ``}`` is encountered, the
+``mkapiref.py`` extracts strings next to ``}`` as the name of enum.
+
+At the time of this writing, Sphinx does not support enum type. So we
+use ``type`` domain for enum it self and ``macro`` domain for each
+value. To refer to the enum value, use ``:enum:`` pseudo role. The
+``mkapiref.py`` replaces it with ``:macro:``. By doing this, when
+Sphinx will support enum officially, we can replace ``:enum:`` with
+the official role easily.
+
+The example follows::
+
+ /**
+ * @enum
+ * Error codes used in the nghttp2 library.
+ */
+ typedef enum {
+ /**
+ * Invalid argument passed.
+ */
+ NGHTTP2_ERR_INVALID_ARGUMENT = -501,
+ /**
+ * Zlib error.
+ */
+ NGHTTP2_ERR_ZLIB = -502,
+ } nghttp2_error;
+
+@struct
+#######
+
+``@struct`` is used to refer to the struct. Currently, only struct
+typedefs are supported. The comment block is used for the document for
+the struct type itself.To document each member, put comment block
+starting with the line ``/**`` and ending with the ``*/`` just before
+the member. When the line starts with ``}`` is encountered, the
+``mkapiref.py`` extracts strings next to ``}`` as the name of struct.
+The block-less typedef is also supported. In this case, typedef
+declaration must be all in one line and the ``mkapiref.py`` uses last
+word as the name of struct.
+
+Some examples follow::
+
+ /**
+ * @struct
+ * The control frame header.
+ */
+ typedef struct {
+ /**
+ * SPDY protocol version.
+ */
+ uint16_t version;
+ /**
+ * The type of this control frame.
+ */
+ uint16_t type;
+ /**
+ * The control frame flags.
+ */
+ uint8_t flags;
+ /**
+ * The length field of this control frame.
+ */
+ int32_t length;
+ } nghttp2_ctrl_hd;
+
+ /**
+ * @struct
+ *
+ * The primary structure to hold the resources needed for a SPDY
+ * session. The details of this structure is hidden from the public
+ * API.
+ */
+ typedef struct nghttp2_session nghttp2_session;
+
+@union
+######
+
+``@union`` is used to refer to the union. Currently, ``@union`` is an
+alias of ``@struct``.
diff --git a/doc/_exts/rubydomain/LICENSE.rubydomain b/doc/_exts/rubydomain/LICENSE.rubydomain
new file mode 100644
index 0000000..a560d75
--- /dev/null
+++ b/doc/_exts/rubydomain/LICENSE.rubydomain
@@ -0,0 +1,28 @@
+If not otherwise noted, the extensions in this package are licensed
+under the following license.
+
+Copyright (c) 2010 by the contributors (see AUTHORS file).
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/doc/_exts/rubydomain/__init__.py b/doc/_exts/rubydomain/__init__.py
new file mode 100644
index 0000000..b5a7dc2
--- /dev/null
+++ b/doc/_exts/rubydomain/__init__.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinxcontrib
+ ~~~~~~~~~~~~~
+
+ This package is a namespace package that contains all extensions
+ distributed in the ``sphinx-contrib`` distribution.
+
+ :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+"""
+
+__import__('pkg_resources').declare_namespace(__name__)
+
diff --git a/doc/_exts/rubydomain/rubydomain.py b/doc/_exts/rubydomain/rubydomain.py
new file mode 100644
index 0000000..db35233
--- /dev/null
+++ b/doc/_exts/rubydomain/rubydomain.py
@@ -0,0 +1,703 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.domains.ruby
+ ~~~~~~~~~~~~~~~~~~~
+
+ The Ruby domain.
+
+ :copyright: Copyright 2010 by SHIBUKAWA Yoshiki
+ :license: BSD, see LICENSE for details.
+"""
+
+import re
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+from docutils.parsers.rst import Directive
+
+from sphinx import addnodes
+from sphinx import version_info
+from sphinx.roles import XRefRole
+from sphinx.locale import _
+from sphinx.domains import Domain, ObjType, Index
+from sphinx.directives import ObjectDescription
+from sphinx.util.nodes import make_refnode
+from sphinx.util.docfields import Field, GroupedField, TypedField
+
+# REs for Ruby signatures
+rb_sig_re = re.compile(
+ r'''^ ([\w.]*\.)? # class name(s)
+ (\$?\w+\??!?) \s* # thing name
+ (?: \((.*)\) # optional: arguments
+ (?:\s* -> \s* (.*))? # return annotation
+ )? $ # and nothing more
+ ''', re.VERBOSE)
+
+rb_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
+
+separators = {
+ 'method':'#', 'attr_reader':'#', 'attr_writer':'#', 'attr_accessor':'#',
+ 'function':'.', 'classmethod':'.', 'class':'::', 'module':'::',
+ 'global':'', 'const':'::'}
+
+rb_separator = re.compile(r"(?:\w+)?(?:::)?(?:\.)?(?:#)?")
+
+
+def _iteritems(d):
+
+ for k in d:
+ yield k, d[k]
+
+
+def ruby_rsplit(fullname):
+ items = [item for item in rb_separator.findall(fullname)]
+ return ''.join(items[:-2]), items[-1]
+
+
+class RubyObject(ObjectDescription):
+ """
+ Description of a general Ruby object.
+ """
+ option_spec = {
+ 'noindex': directives.flag,
+ 'module': directives.unchanged,
+ }
+
+ doc_field_types = [
+ TypedField('parameter', label=_('Parameters'),
+ names=('param', 'parameter', 'arg', 'argument'),
+ typerolename='obj', typenames=('paramtype', 'type')),
+ TypedField('variable', label=_('Variables'), rolename='obj',
+ names=('var', 'ivar', 'cvar'),
+ typerolename='obj', typenames=('vartype',)),
+ GroupedField('exceptions', label=_('Raises'), rolename='exc',
+ names=('raises', 'raise', 'exception', 'except'),
+ can_collapse=True),
+ Field('returnvalue', label=_('Returns'), has_arg=False,
+ names=('returns', 'return')),
+ Field('returntype', label=_('Return type'), has_arg=False,
+ names=('rtype',)),
+ ]
+
+ def get_signature_prefix(self, sig):
+ """
+ May return a prefix to put before the object name in the signature.
+ """
+ return ''
+
+ def needs_arglist(self):
+ """
+ May return true if an empty argument list is to be generated even if
+ the document contains none.
+ """
+ return False
+
+ def handle_signature(self, sig, signode):
+ """
+ Transform a Ruby signature into RST nodes.
+ Returns (fully qualified name of the thing, classname if any).
+
+ If inside a class, the current class name is handled intelligently:
+ * it is stripped from the displayed name if present
+ * it is added to the full name (return value) if not present
+ """
+ m = rb_sig_re.match(sig)
+ if m is None:
+ raise ValueError
+ name_prefix, name, arglist, retann = m.groups()
+ if not name_prefix:
+ name_prefix = ""
+ # determine module and class name (if applicable), as well as full name
+ modname = self.options.get(
+ 'module', self.env.temp_data.get('rb:module'))
+ classname = self.env.temp_data.get('rb:class')
+ if self.objtype == 'global':
+ add_module = False
+ modname = None
+ classname = None
+ fullname = name
+ elif classname:
+ add_module = False
+ if name_prefix and name_prefix.startswith(classname):
+ fullname = name_prefix + name
+ # class name is given again in the signature
+ name_prefix = name_prefix[len(classname):].lstrip('.')
+ else:
+ separator = separators[self.objtype]
+ fullname = classname + separator + name_prefix + name
+ else:
+ add_module = True
+ if name_prefix:
+ classname = name_prefix.rstrip('.')
+ fullname = name_prefix + name
+ else:
+ classname = ''
+ fullname = name
+
+ signode['module'] = modname
+ signode['class'] = self.class_name = classname
+ signode['fullname'] = fullname
+
+ sig_prefix = self.get_signature_prefix(sig)
+ if sig_prefix:
+ signode += addnodes.desc_annotation(sig_prefix, sig_prefix)
+
+ if name_prefix:
+ signode += addnodes.desc_addname(name_prefix, name_prefix)
+ # exceptions are a special case, since they are documented in the
+ # 'exceptions' module.
+ elif add_module and self.env.config.add_module_names:
+ if self.objtype == 'global':
+ nodetext = ''
+ signode += addnodes.desc_addname(nodetext, nodetext)
+ else:
+ modname = self.options.get(
+ 'module', self.env.temp_data.get('rb:module'))
+ if modname and modname != 'exceptions':
+ nodetext = modname + separators[self.objtype]
+ signode += addnodes.desc_addname(nodetext, nodetext)
+
+ signode += addnodes.desc_name(name, name)
+ if not arglist:
+ if self.needs_arglist():
+ # for callables, add an empty parameter list
+ signode += addnodes.desc_parameterlist()
+ if retann:
+ signode += addnodes.desc_returns(retann, retann)
+ return fullname, name_prefix
+ signode += addnodes.desc_parameterlist()
+
+ stack = [signode[-1]]
+ for token in rb_paramlist_re.split(arglist):
+ if token == '[':
+ opt = addnodes.desc_optional()
+ stack[-1] += opt
+ stack.append(opt)
+ elif token == ']':
+ try:
+ stack.pop()
+ except IndexError:
+ raise ValueError
+ elif not token or token == ',' or token.isspace():
+ pass
+ else:
+ token = token.strip()
+ stack[-1] += addnodes.desc_parameter(token, token)
+ if len(stack) != 1:
+ raise ValueError
+ if retann:
+ signode += addnodes.desc_returns(retann, retann)
+ return fullname, name_prefix
+
+ def get_index_text(self, modname, name):
+ """
+ Return the text for the index entry of the object.
+ """
+ raise NotImplementedError('must be implemented in subclasses')
+
+ def _is_class_member(self):
+ return self.objtype.endswith('method') or self.objtype.startswith('attr')
+
+ def add_target_and_index(self, name_cls, sig, signode):
+ if self.objtype == 'global':
+ modname = ''
+ else:
+ modname = self.options.get(
+ 'module', self.env.temp_data.get('rb:module'))
+ separator = separators[self.objtype]
+ if self._is_class_member():
+ if signode['class']:
+ prefix = modname and modname + '::' or ''
+ else:
+ prefix = modname and modname + separator or ''
+ else:
+ prefix = modname and modname + separator or ''
+ fullname = prefix + name_cls[0]
+ # note target
+ if fullname not in self.state.document.ids:
+ signode['names'].append(fullname)
+ signode['ids'].append(fullname)
+ signode['first'] = (not self.names)
+ self.state.document.note_explicit_target(signode)
+ objects = self.env.domaindata['rb']['objects']
+ if fullname in objects:
+ self.env.warn(
+ self.env.docname,
+ 'duplicate object description of %s, ' % fullname +
+ 'other instance in ' +
+ self.env.doc2path(objects[fullname][0]),
+ self.lineno)
+ objects[fullname] = (self.env.docname, self.objtype)
+
+ indextext = self.get_index_text(modname, name_cls)
+ if indextext:
+ self.indexnode['entries'].append(
+ _make_index('single', indextext, fullname, fullname))
+
+ def before_content(self):
+ # needed for automatic qualification of members (reset in subclasses)
+ self.clsname_set = False
+
+ def after_content(self):
+ if self.clsname_set:
+ self.env.temp_data['rb:class'] = None
+
+
+class RubyModulelevel(RubyObject):
+ """
+ Description of an object on module level (functions, data).
+ """
+
+ def needs_arglist(self):
+ return self.objtype == 'function'
+
+ def get_index_text(self, modname, name_cls):
+ if self.objtype == 'function':
+ if not modname:
+ return _('%s() (global function)') % name_cls[0]
+ return _('%s() (module function in %s)') % (name_cls[0], modname)
+ else:
+ return ''
+
+
+class RubyGloballevel(RubyObject):
+ """
+ Description of an object on module level (functions, data).
+ """
+
+ def get_index_text(self, modname, name_cls):
+ if self.objtype == 'global':
+ return _('%s (global variable)') % name_cls[0]
+ else:
+ return ''
+
+
+class RubyEverywhere(RubyObject):
+ """
+ Description of a class member (methods, attributes).
+ """
+
+ def needs_arglist(self):
+ return self.objtype == 'method'
+
+ def get_index_text(self, modname, name_cls):
+ name, cls = name_cls
+ add_modules = self.env.config.add_module_names
+ if self.objtype == 'method':
+ try:
+ clsname, methname = ruby_rsplit(name)
+ except ValueError:
+ if modname:
+ return _('%s() (in module %s)') % (name, modname)
+ else:
+ return '%s()' % name
+ if modname and add_modules:
+ return _('%s() (%s::%s method)') % (methname, modname,
+ clsname)
+ else:
+ return _('%s() (%s method)') % (methname, clsname)
+ else:
+ return ''
+
+
+class RubyClasslike(RubyObject):
+ """
+ Description of a class-like object (classes, exceptions).
+ """
+
+ def get_signature_prefix(self, sig):
+ return self.objtype + ' '
+
+ def get_index_text(self, modname, name_cls):
+ if self.objtype == 'class':
+ if not modname:
+ return _('%s (class)') % name_cls[0]
+ return _('%s (class in %s)') % (name_cls[0], modname)
+ elif self.objtype == 'exception':
+ return name_cls[0]
+ else:
+ return ''
+
+ def before_content(self):
+ RubyObject.before_content(self)
+ if self.names:
+ self.env.temp_data['rb:class'] = self.names[0][0]
+ self.clsname_set = True
+
+
+class RubyClassmember(RubyObject):
+ """
+ Description of a class member (methods, attributes).
+ """
+
+ def needs_arglist(self):
+ return self.objtype.endswith('method')
+
+ def get_signature_prefix(self, sig):
+ if self.objtype == 'classmethod':
+ return "classmethod %s." % self.class_name
+ elif self.objtype == 'attr_reader':
+ return "attribute [R] "
+ elif self.objtype == 'attr_writer':
+ return "attribute [W] "
+ elif self.objtype == 'attr_accessor':
+ return "attribute [R/W] "
+ return ''
+
+ def get_index_text(self, modname, name_cls):
+ name, cls = name_cls
+ add_modules = self.env.config.add_module_names
+ if self.objtype == 'classmethod':
+ try:
+ clsname, methname = ruby_rsplit(name)
+ except ValueError:
+ return '%s()' % name
+ if modname:
+ return _('%s() (%s.%s class method)') % (methname, modname,
+ clsname)
+ else:
+ return _('%s() (%s class method)') % (methname, clsname)
+ elif self.objtype.startswith('attr'):
+ try:
+ clsname, attrname = ruby_rsplit(name)
+ except ValueError:
+ return name
+ if modname and add_modules:
+ return _('%s (%s.%s attribute)') % (attrname, modname, clsname)
+ else:
+ return _('%s (%s attribute)') % (attrname, clsname)
+ else:
+ return ''
+
+ def before_content(self):
+ RubyObject.before_content(self)
+ lastname = self.names and self.names[-1][1]
+ if lastname and not self.env.temp_data.get('rb:class'):
+ self.env.temp_data['rb:class'] = lastname.strip('.')
+ self.clsname_set = True
+
+
+class RubyModule(Directive):
+ """
+ Directive to mark description of a new module.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {
+ 'platform': lambda x: x,
+ 'synopsis': lambda x: x,
+ 'noindex': directives.flag,
+ 'deprecated': directives.flag,
+ }
+
+ def run(self):
+ env = self.state.document.settings.env
+ modname = self.arguments[0].strip()
+ noindex = 'noindex' in self.options
+ env.temp_data['rb:module'] = modname
+ env.domaindata['rb']['modules'][modname] = \
+ (env.docname, self.options.get('synopsis', ''),
+ self.options.get('platform', ''), 'deprecated' in self.options)
+ targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True)
+ self.state.document.note_explicit_target(targetnode)
+ ret = [targetnode]
+ # XXX this behavior of the module directive is a mess...
+ if 'platform' in self.options:
+ platform = self.options['platform']
+ node = nodes.paragraph()
+ node += nodes.emphasis('', _('Platforms: '))
+ node += nodes.Text(platform, platform)
+ ret.append(node)
+ # the synopsis isn't printed; in fact, it is only used in the
+ # modindex currently
+ if not noindex:
+ indextext = _('%s (module)') % modname
+ inode = addnodes.index(entries=[_make_index(
+ 'single', indextext, 'module-' + modname, modname)])
+ ret.append(inode)
+ return ret
+
+def _make_index(entrytype, entryname, target, ignored, key=None):
+ # Sphinx 1.4 introduced backward incompatible changes, it now
+ # requires 5 tuples. Last one is categorization key. See
+ # http://www.sphinx-doc.org/en/stable/extdev/nodes.html#sphinx.addnodes.index
+ if version_info >= (1, 4, 0, '', 0):
+ return (entrytype, entryname, target, ignored, key)
+ else:
+ return (entrytype, entryname, target, ignored)
+
+class RubyCurrentModule(Directive):
+ """
+ This directive is just to tell Sphinx that we're documenting
+ stuff in module foo, but links to module foo won't lead here.
+ """
+
+ has_content = False
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = False
+ option_spec = {}
+
+ def run(self):
+ env = self.state.document.settings.env
+ modname = self.arguments[0].strip()
+ if modname == 'None':
+ env.temp_data['rb:module'] = None
+ else:
+ env.temp_data['rb:module'] = modname
+ return []
+
+
+class RubyXRefRole(XRefRole):
+ def process_link(self, env, refnode, has_explicit_title, title, target):
+ if not has_explicit_title:
+ title = title.lstrip('.') # only has a meaning for the target
+ title = title.lstrip('#')
+ if title.startswith("::"):
+ title = title[2:]
+ target = target.lstrip('~') # only has a meaning for the title
+ # if the first character is a tilde, don't display the module/class
+ # parts of the contents
+ if title[0:1] == '~':
+ m = re.search(r"(?:\.)?(?:#)?(?:::)?(.*)\Z", title)
+ if m:
+ title = m.group(1)
+ if not title.startswith("$"):
+ refnode['rb:module'] = env.temp_data.get('rb:module')
+ refnode['rb:class'] = env.temp_data.get('rb:class')
+ # if the first character is a dot, search more specific namespaces first
+ # else search builtins first
+ if target[0:1] == '.':
+ target = target[1:]
+ refnode['refspecific'] = True
+ return title, target
+
+
+class RubyModuleIndex(Index):
+ """
+ Index subclass to provide the Ruby module index.
+ """
+
+ name = 'modindex'
+ localname = _('Ruby Module Index')
+ shortname = _('modules')
+
+ def generate(self, docnames=None):
+ content = {}
+ # list of prefixes to ignore
+ ignores = self.domain.env.config['modindex_common_prefix']
+ ignores = sorted(ignores, key=len, reverse=True)
+ # list of all modules, sorted by module name
+ modules = sorted(_iteritems(self.domain.data['modules']),
+ key=lambda x: x[0].lower())
+ # sort out collapsible modules
+ prev_modname = ''
+ num_toplevels = 0
+ for modname, (docname, synopsis, platforms, deprecated) in modules:
+ if docnames and docname not in docnames:
+ continue
+
+ for ignore in ignores:
+ if modname.startswith(ignore):
+ modname = modname[len(ignore):]
+ stripped = ignore
+ break
+ else:
+ stripped = ''
+
+ # we stripped the whole module name?
+ if not modname:
+ modname, stripped = stripped, ''
+
+ entries = content.setdefault(modname[0].lower(), [])
+
+ package = modname.split('::')[0]
+ if package != modname:
+ # it's a submodule
+ if prev_modname == package:
+ # first submodule - make parent a group head
+ entries[-1][1] = 1
+ elif not prev_modname.startswith(package):
+ # submodule without parent in list, add dummy entry
+ entries.append([stripped + package, 1, '', '', '', '', ''])
+ subtype = 2
+ else:
+ num_toplevels += 1
+ subtype = 0
+
+ qualifier = deprecated and _('Deprecated') or ''
+ entries.append([stripped + modname, subtype, docname,
+ 'module-' + stripped + modname, platforms,
+ qualifier, synopsis])
+ prev_modname = modname
+
+ # apply heuristics when to collapse modindex at page load:
+ # only collapse if number of toplevel modules is larger than
+ # number of submodules
+ collapse = len(modules) - num_toplevels < num_toplevels
+
+ # sort by first letter
+ content = sorted(_iteritems(content))
+
+ return content, collapse
+
+
+class RubyDomain(Domain):
+ """Ruby language domain."""
+ name = 'rb'
+ label = 'Ruby'
+ object_types = {
+ 'function': ObjType(_('function'), 'func', 'obj'),
+ 'global': ObjType(_('global variable'), 'global', 'obj'),
+ 'method': ObjType(_('method'), 'meth', 'obj'),
+ 'class': ObjType(_('class'), 'class', 'obj'),
+ 'exception': ObjType(_('exception'), 'exc', 'obj'),
+ 'classmethod': ObjType(_('class method'), 'meth', 'obj'),
+ 'attr_reader': ObjType(_('attribute'), 'attr', 'obj'),
+ 'attr_writer': ObjType(_('attribute'), 'attr', 'obj'),
+ 'attr_accessor': ObjType(_('attribute'), 'attr', 'obj'),
+ 'const': ObjType(_('const'), 'const', 'obj'),
+ 'module': ObjType(_('module'), 'mod', 'obj'),
+ }
+
+ directives = {
+ 'function': RubyModulelevel,
+ 'global': RubyGloballevel,
+ 'method': RubyEverywhere,
+ 'const': RubyEverywhere,
+ 'class': RubyClasslike,
+ 'exception': RubyClasslike,
+ 'classmethod': RubyClassmember,
+ 'attr_reader': RubyClassmember,
+ 'attr_writer': RubyClassmember,
+ 'attr_accessor': RubyClassmember,
+ 'module': RubyModule,
+ 'currentmodule': RubyCurrentModule,
+ }
+
+ roles = {
+ 'func': RubyXRefRole(fix_parens=False),
+ 'global':RubyXRefRole(),
+ 'class': RubyXRefRole(),
+ 'exc': RubyXRefRole(),
+ 'meth': RubyXRefRole(fix_parens=False),
+ 'attr': RubyXRefRole(),
+ 'const': RubyXRefRole(),
+ 'mod': RubyXRefRole(),
+ 'obj': RubyXRefRole(),
+ }
+ initial_data = {
+ 'objects': {}, # fullname -> docname, objtype
+ 'modules': {}, # modname -> docname, synopsis, platform, deprecated
+ }
+ indices = [
+ RubyModuleIndex,
+ ]
+
+ def clear_doc(self, docname):
+ for fullname, (fn, _) in list(self.data['objects'].items()):
+ if fn == docname:
+ del self.data['objects'][fullname]
+ for modname, (fn, _, _, _) in list(self.data['modules'].items()):
+ if fn == docname:
+ del self.data['modules'][modname]
+
+ def find_obj(self, env, modname, classname, name, type, searchorder=0):
+ """
+ Find a Ruby object for "name", perhaps using the given module and/or
+ classname.
+ """
+ # skip parens
+ if name[-2:] == '()':
+ name = name[:-2]
+
+ if not name:
+ return None, None
+
+ objects = self.data['objects']
+
+ newname = None
+ if searchorder == 1:
+ if modname and classname and \
+ modname + '::' + classname + '#' + name in objects:
+ newname = modname + '::' + classname + '#' + name
+ elif modname and classname and \
+ modname + '::' + classname + '.' + name in objects:
+ newname = modname + '::' + classname + '.' + name
+ elif modname and modname + '::' + name in objects:
+ newname = modname + '::' + name
+ elif modname and modname + '#' + name in objects:
+ newname = modname + '#' + name
+ elif modname and modname + '.' + name in objects:
+ newname = modname + '.' + name
+ elif classname and classname + '.' + name in objects:
+ newname = classname + '.' + name
+ elif classname and classname + '#' + name in objects:
+ newname = classname + '#' + name
+ elif name in objects:
+ newname = name
+ else:
+ if name in objects:
+ newname = name
+ elif classname and classname + '.' + name in objects:
+ newname = classname + '.' + name
+ elif classname and classname + '#' + name in objects:
+ newname = classname + '#' + name
+ elif modname and modname + '::' + name in objects:
+ newname = modname + '::' + name
+ elif modname and modname + '#' + name in objects:
+ newname = modname + '#' + name
+ elif modname and modname + '.' + name in objects:
+ newname = modname + '.' + name
+ elif modname and classname and \
+ modname + '::' + classname + '#' + name in objects:
+ newname = modname + '::' + classname + '#' + name
+ elif modname and classname and \
+ modname + '::' + classname + '.' + name in objects:
+ newname = modname + '::' + classname + '.' + name
+ # special case: object methods
+ elif type in ('func', 'meth') and '.' not in name and \
+ 'object.' + name in objects:
+ newname = 'object.' + name
+ if newname is None:
+ return None, None
+ return newname, objects[newname]
+
+ def resolve_xref(self, env, fromdocname, builder,
+ typ, target, node, contnode):
+ if (typ == 'mod' or
+ typ == 'obj' and target in self.data['modules']):
+ docname, synopsis, platform, deprecated = \
+ self.data['modules'].get(target, ('','','', ''))
+ if not docname:
+ return None
+ else:
+ title = '%s%s%s' % ((platform and '(%s) ' % platform),
+ synopsis,
+ (deprecated and ' (deprecated)' or ''))
+ return make_refnode(builder, fromdocname, docname,
+ 'module-' + target, contnode, title)
+ else:
+ modname = node.get('rb:module')
+ clsname = node.get('rb:class')
+ searchorder = node.hasattr('refspecific') and 1 or 0
+ name, obj = self.find_obj(env, modname, clsname,
+ target, typ, searchorder)
+ if not obj:
+ return None
+ else:
+ return make_refnode(builder, fromdocname, obj[0], name,
+ contnode, name)
+
+ def get_objects(self):
+ for modname, info in _iteritems(self.data['modules']):
+ yield (modname, modname, 'module', info[0], 'module-' + modname, 0)
+ for refname, (docname, type) in _iteritems(self.data['objects']):
+ yield (refname, refname, type, docname, refname, 1)
+
+
+def setup(app):
+ app.add_domain(RubyDomain)
diff --git a/doc/bash_completion/h2load b/doc/bash_completion/h2load
new file mode 100644
index 0000000..2b2d4ab
--- /dev/null
+++ b/doc/bash_completion/h2load
@@ -0,0 +1,19 @@
+_h2load()
+{
+ local cur prev split=false
+ COMPREPLY=()
+ COMP_WORDBREAKS=${COMP_WORDBREAKS//=}
+
+ cmd=${COMP_WORDS[0]}
+ _get_comp_words_by_ref cur prev
+ case $cur in
+ -*)
+ COMPREPLY=( $( compgen -W '--requests --clients --threads --input-file --max-concurrent-streams --max-frame-size --window-bits --connection-window-bits --header --ciphers --tls13-ciphers --no-tls-proto --data --rate --rate-period --duration --warm-up-time --connection-active-timeout --connection-inactivity-timeout --timing-script-file --base-uri --alpn-list --h1 --header-table-size --encoder-header-table-size --log-file --qlog-file-base --connect-to --rps --groups --no-udp-gso --max-udp-payload-size --ktls --verbose --version --help ' -- "$cur" ) )
+ ;;
+ *)
+ _filedir
+ return 0
+ esac
+ return 0
+}
+complete -F _h2load h2load
diff --git a/doc/bash_completion/make_bash_completion.py b/doc/bash_completion/make_bash_completion.py
new file mode 100755
index 0000000..e3a535b
--- /dev/null
+++ b/doc/bash_completion/make_bash_completion.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import subprocess
+import io
+import re
+import sys
+import os.path
+
+class Option:
+ def __init__(self, long_opt, short_opt):
+ self.long_opt = long_opt
+ self.short_opt = short_opt
+
+def get_all_options(cmd):
+ opt_pattern = re.compile(r' (?:(-.), )?(--[^\s\[=]+)(\[)?')
+ proc = subprocess.Popen([cmd, "--help"], stdout=subprocess.PIPE)
+ stdoutdata, _ = proc.communicate()
+ cur_option = None
+ opts = {}
+ for line in io.StringIO(stdoutdata.decode('utf-8')):
+ match = opt_pattern.match(line)
+ if not match:
+ continue
+ long_opt = match.group(2)
+ short_opt = match.group(1)
+ opts[long_opt] = Option(long_opt, short_opt)
+
+ return opts
+
+def output_case(out, name, opts):
+ out.write('''\
+_{name}()
+{{
+ local cur prev split=false
+ COMPREPLY=()
+ COMP_WORDBREAKS=${{COMP_WORDBREAKS//=}}
+
+ cmd=${{COMP_WORDS[0]}}
+ _get_comp_words_by_ref cur prev
+'''.format(name=name))
+
+ # Complete option name.
+ out.write('''\
+ case $cur in
+ -*)
+ COMPREPLY=( $( compgen -W '\
+''')
+ for opt in opts.values():
+ out.write(opt.long_opt)
+ out.write(' ')
+
+ out.write('''\
+' -- "$cur" ) )
+ ;;
+''')
+ # If no option found for completion then complete with files.
+ out.write('''\
+ *)
+ _filedir
+ return 0
+ esac
+ return 0
+}}
+complete -F _{name} {name}
+'''.format(name=name))
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print("Generates bash_completion using `/path/to/cmd --help'")
+ print("Usage: make_bash_completion.py /path/to/cmd")
+ exit(1)
+ name = os.path.basename(sys.argv[1])
+ opts = get_all_options(sys.argv[1])
+ output_case(sys.stdout, name, opts)
diff --git a/doc/bash_completion/nghttp b/doc/bash_completion/nghttp
new file mode 100644
index 0000000..dd48403
--- /dev/null
+++ b/doc/bash_completion/nghttp
@@ -0,0 +1,19 @@
+_nghttp()
+{
+ local cur prev split=false
+ COMPREPLY=()
+ COMP_WORDBREAKS=${COMP_WORDBREAKS//=}
+
+ cmd=${COMP_WORDS[0]}
+ _get_comp_words_by_ref cur prev
+ case $cur in
+ -*)
+ COMPREPLY=( $( compgen -W '--verbose --null-out --remote-name --timeout --window-bits --connection-window-bits --get-assets --stat --header --trailer --cert --key --data --multiply --upgrade --weight --peer-max-concurrent-streams --header-table-size --encoder-header-table-size --padding --har --color --continuation --no-content-length --no-dep --hexdump --no-push --max-concurrent-streams --expect-continue --no-verify-peer --ktls --no-rfc7540-pri --version --help ' -- "$cur" ) )
+ ;;
+ *)
+ _filedir
+ return 0
+ esac
+ return 0
+}
+complete -F _nghttp nghttp
diff --git a/doc/bash_completion/nghttpd b/doc/bash_completion/nghttpd
new file mode 100644
index 0000000..7dd4d9b
--- /dev/null
+++ b/doc/bash_completion/nghttpd
@@ -0,0 +1,19 @@
+_nghttpd()
+{
+ local cur prev split=false
+ COMPREPLY=()
+ COMP_WORDBREAKS=${COMP_WORDBREAKS//=}
+
+ cmd=${COMP_WORDS[0]}
+ _get_comp_words_by_ref cur prev
+ case $cur in
+ -*)
+ COMPREPLY=( $( compgen -W '--address --daemon --verify-client --htdocs --verbose --no-tls --header-table-size --encoder-header-table-size --color --push --padding --max-concurrent-streams --workers --error-gzip --window-bits --connection-window-bits --dh-param-file --early-response --trailer --hexdump --echo-upload --mime-types-file --no-content-length --ktls --no-rfc7540-pri --version --help ' -- "$cur" ) )
+ ;;
+ *)
+ _filedir
+ return 0
+ esac
+ return 0
+}
+complete -F _nghttpd nghttpd
diff --git a/doc/bash_completion/nghttpx b/doc/bash_completion/nghttpx
new file mode 100644
index 0000000..a735cd2
--- /dev/null
+++ b/doc/bash_completion/nghttpx
@@ -0,0 +1,19 @@
+_nghttpx()
+{
+ local cur prev split=false
+ COMPREPLY=()
+ COMP_WORDBREAKS=${COMP_WORDBREAKS//=}
+
+ cmd=${COMP_WORDS[0]}
+ _get_comp_words_by_ref cur prev
+ case $cur in
+ -*)
+ COMPREPLY=( $( compgen -W '--backend --frontend --backlog --backend-address-family --backend-http-proxy-uri --workers --single-thread --read-rate --read-burst --write-rate --write-burst --worker-read-rate --worker-read-burst --worker-write-rate --worker-write-burst --worker-frontend-connections --backend-connections-per-host --backend-connections-per-frontend --rlimit-nofile --rlimit-memlock --backend-request-buffer --backend-response-buffer --fastopen --no-kqueue --frontend-http2-read-timeout --frontend-http3-read-timeout --frontend-read-timeout --frontend-write-timeout --frontend-keep-alive-timeout --stream-read-timeout --stream-write-timeout --backend-read-timeout --backend-write-timeout --backend-connect-timeout --backend-keep-alive-timeout --listener-disable-timeout --frontend-http2-setting-timeout --backend-http2-settings-timeout --backend-max-backoff --ciphers --tls13-ciphers --client-ciphers --tls13-client-ciphers --ecdh-curves --insecure --cacert --private-key-passwd-file --subcert --dh-param-file --alpn-list --verify-client --verify-client-cacert --verify-client-tolerate-expired --client-private-key-file --client-cert-file --tls-min-proto-version --tls-max-proto-version --tls-ticket-key-file --tls-ticket-key-memcached --tls-ticket-key-memcached-address-family --tls-ticket-key-memcached-interval --tls-ticket-key-memcached-max-retry --tls-ticket-key-memcached-max-fail --tls-ticket-key-cipher --tls-ticket-key-memcached-cert-file --tls-ticket-key-memcached-private-key-file --fetch-ocsp-response-file --ocsp-update-interval --ocsp-startup --no-verify-ocsp --no-ocsp --tls-session-cache-memcached --tls-session-cache-memcached-address-family --tls-session-cache-memcached-cert-file --tls-session-cache-memcached-private-key-file --tls-dyn-rec-warmup-threshold --tls-dyn-rec-idle-timeout --no-http2-cipher-block-list --client-no-http2-cipher-block-list --tls-sct-dir --psk-secrets --client-psk-secrets --tls-no-postpone-early-data --tls-max-early-data --tls-ktls --frontend-http2-max-concurrent-streams --backend-http2-max-concurrent-streams --frontend-http2-window-size --frontend-http2-connection-window-size --backend-http2-window-size --backend-http2-connection-window-size --http2-no-cookie-crumbling --padding --no-server-push --frontend-http2-optimize-write-buffer-size --frontend-http2-optimize-window-size --frontend-http2-encoder-dynamic-table-size --frontend-http2-decoder-dynamic-table-size --backend-http2-encoder-dynamic-table-size --backend-http2-decoder-dynamic-table-size --http2-proxy --log-level --accesslog-file --accesslog-syslog --accesslog-format --accesslog-write-early --errorlog-file --errorlog-syslog --syslog-facility --add-x-forwarded-for --strip-incoming-x-forwarded-for --no-add-x-forwarded-proto --no-strip-incoming-x-forwarded-proto --add-forwarded --strip-incoming-forwarded --forwarded-by --forwarded-for --no-via --no-strip-incoming-early-data --no-location-rewrite --host-rewrite --altsvc --http2-altsvc --add-request-header --add-response-header --request-header-field-buffer --max-request-header-fields --response-header-field-buffer --max-response-header-fields --error-page --server-name --no-server-rewrite --redirect-https-port --require-http-scheme --api-max-request-body --dns-cache-timeout --dns-lookup-timeout --dns-max-try --frontend-max-requests --frontend-http2-dump-request-header --frontend-http2-dump-response-header --frontend-frame-debug --daemon --pid-file --user --single-process --max-worker-processes --worker-process-grace-shutdown-period --mruby-file --ignore-per-pattern-mruby-error --frontend-quic-idle-timeout --frontend-quic-debug-log --quic-bpf-program-file --frontend-quic-early-data --frontend-quic-qlog-dir --frontend-quic-require-token --frontend-quic-congestion-controller --frontend-quic-secret-file --quic-server-id --frontend-quic-initial-rtt --no-quic-bpf --frontend-http3-window-size --frontend-http3-connection-window-size --frontend-http3-max-window-size --frontend-http3-max-connection-window-size --frontend-http3-max-concurrent-streams --conf --include --version --help ' -- "$cur" ) )
+ ;;
+ *)
+ _filedir
+ return 0
+ esac
+ return 0
+}
+complete -F _nghttpx nghttpx
diff --git a/doc/building-android-binary.rst.in b/doc/building-android-binary.rst.in
new file mode 100644
index 0000000..2c77c98
--- /dev/null
+++ b/doc/building-android-binary.rst.in
@@ -0,0 +1 @@
+.. include:: @top_srcdir@/doc/sources/building-android-binary.rst
diff --git a/doc/conf.py.in b/doc/conf.py.in
new file mode 100644
index 0000000..228bdb1
--- /dev/null
+++ b/doc/conf.py.in
@@ -0,0 +1,252 @@
+# -*- coding: utf-8 -*-
+# nghttp2 - HTTP/2 C Library
+
+# Copyright (c) 2012 Tatsuhiro Tsujikawa
+
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#
+# nghttp2 documentation build configuration file, created by
+# sphinx-quickstart on Sun Mar 11 22:57:49 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+sys.path.insert(0, os.path.abspath('@top_srcdir@/doc/_exts'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['rubydomain.rubydomain']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['@top_srcdir@/_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'nghttp2'
+copyright = u'2012, 2015, 2016, Tatsuhiro Tsujikawa'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '@PACKAGE_VERSION@'
+# The full version, including alpha/beta/rc tags.
+release = '@PACKAGE_VERSION@'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['manual', 'README.rst', '*-header.rst', 'sources']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+default_role = 'c:func'
+primary_domain = 'c'
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The default language to highlight source code in. The default is 'python'.
+highlight_language = 'c'
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'sphinx_rtd_theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = ['@top_srcdir@/doc/_themes']
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = False
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {
+ '**': ['menu.html', 'localtoc.html', 'relations.html', 'sourcelink.html',
+ 'searchbox.html']
+ }
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = False
+html_copy_source = False
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'nghttp2doc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'nghttp2.tex', u'nghttp2 Documentation',
+ u'Tatsuhiro Tsujikawa', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('nghttp.1', 'nghttp', u'HTTP/2 client', [u'Tatsuhiro Tsujikawa'], 1),
+ ('nghttpd.1', 'nghttpd', u'HTTP/2 server', [u'Tatsuhiro Tsujikawa'], 1),
+ ('nghttpx.1', 'nghttpx', u'HTTP/2 proxy', [u'Tatsuhiro Tsujikawa'], 1),
+ ('h2load.1', 'h2load', u'HTTP/2 benchmarking tool',
+ [u'Tatsuhiro Tsujikawa'], 1)
+]
diff --git a/doc/contribute.rst.in b/doc/contribute.rst.in
new file mode 100644
index 0000000..6a229d4
--- /dev/null
+++ b/doc/contribute.rst.in
@@ -0,0 +1 @@
+.. include:: @top_srcdir@/doc/sources/contribute.rst
diff --git a/doc/docutils.conf b/doc/docutils.conf
new file mode 100644
index 0000000..f5208a8
--- /dev/null
+++ b/doc/docutils.conf
@@ -0,0 +1,2 @@
+[parsers]
+smart_quotes=no
diff --git a/doc/h2load-howto.rst.in b/doc/h2load-howto.rst.in
new file mode 100644
index 0000000..252069d
--- /dev/null
+++ b/doc/h2load-howto.rst.in
@@ -0,0 +1 @@
+.. include:: @top_srcdir@/doc/sources/h2load-howto.rst
diff --git a/doc/h2load.1 b/doc/h2load.1
new file mode 100644
index 0000000..df052ab
--- /dev/null
+++ b/doc/h2load.1
@@ -0,0 +1,530 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "H2LOAD" "1" "Jan 21, 2024" "1.59.0" "nghttp2"
+.SH NAME
+h2load \- HTTP/2 benchmarking tool
+.SH SYNOPSIS
+.sp
+\fBh2load\fP [OPTIONS]... [URI]...
+.SH DESCRIPTION
+.sp
+benchmarking tool for HTTP/2 server
+.INDENT 0.0
+.TP
+.B <URI>
+Specify URI to access. Multiple URIs can be specified.
+URIs are used in this order for each client. All URIs
+are used, then first URI is used and then 2nd URI, and
+so on. The scheme, host and port in the subsequent
+URIs, if present, are ignored. Those in the first URI
+are used solely. Definition of a base URI overrides all
+scheme, host or port values.
+.UNINDENT
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B \-n, \-\-requests=<N>
+Number of requests across all clients. If it is used
+with \fI\%\-\-timing\-script\-file\fP option, this option specifies
+the number of requests each client performs rather than
+the number of requests across all clients. This option
+is ignored if timing\-based benchmarking is enabled (see
+\fI\%\-\-duration\fP option).
+.sp
+Default: \fB1\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-c, \-\-clients=<N>
+Number of concurrent clients. With \fI\%\-r\fP option, this
+specifies the maximum number of connections to be made.
+.sp
+Default: \fB1\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-t, \-\-threads=<N>
+Number of native threads.
+.sp
+Default: \fB1\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-i, \-\-input\-file=<PATH>
+Path of a file with multiple URIs are separated by EOLs.
+This option will disable URIs getting from command\-line.
+If \(aq\-\(aq is given as <PATH>, URIs will be read from stdin.
+URIs are used in this order for each client. All URIs
+are used, then first URI is used and then 2nd URI, and
+so on. The scheme, host and port in the subsequent
+URIs, if present, are ignored. Those in the first URI
+are used solely. Definition of a base URI overrides all
+scheme, host or port values.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-m, \-\-max\-concurrent\-streams=<N>
+Max concurrent streams to issue per session. When
+http/1.1 is used, this specifies the number of HTTP
+pipelining requests in\-flight.
+.sp
+Default: \fB1\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-f, \-\-max\-frame\-size=<SIZE>
+Maximum frame size that the local endpoint is willing to
+receive.
+.sp
+Default: \fB16K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-w, \-\-window\-bits=<N>
+Sets the stream level initial window size to (2**<N>)\-1.
+For QUIC, <N> is capped to 26 (roughly 64MiB).
+.sp
+Default: \fB30\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-W, \-\-connection\-window\-bits=<N>
+Sets the connection level initial window size to
+(2**<N>)\-1.
+.sp
+Default: \fB30\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-H, \-\-header=<HEADER>
+Add/Override a header to the requests.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ciphers=<SUITE>
+Set allowed cipher list for TLSv1.2 or earlier. The
+format of the string is described in OpenSSL ciphers(1).
+.sp
+Default: \fBECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:DHE\-RSA\-AES128\-GCM\-SHA256:DHE\-RSA\-AES256\-GCM\-SHA384\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls13\-ciphers=<SUITE>
+Set allowed cipher list for TLSv1.3. The format of the
+string is described in OpenSSL ciphers(1).
+.sp
+Default: \fBTLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-p, \-\-no\-tls\-proto=<PROTOID>
+Specify ALPN identifier of the protocol to be used when
+accessing http URI without SSL/TLS.
+Available protocols: h2c and http/1.1
+.sp
+Default: \fBh2c\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-d, \-\-data=<PATH>
+Post FILE to server. The request method is changed to
+POST. For http/1.1 connection, if \fI\%\-d\fP is used, the
+maximum number of in\-flight pipelined requests is set to
+1.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-r, \-\-rate=<N>
+Specifies the fixed rate at which connections are
+created. The rate must be a positive integer,
+representing the number of connections to be made per
+rate period. The maximum number of connections to be
+made is given in \fI\%\-c\fP option. This rate will be
+distributed among threads as evenly as possible. For
+example, with \fI\%\-t\fP2 and \fI\%\-r\fP4, each thread gets 2
+connections per period. When the rate is 0, the program
+will run as it normally does, creating connections at
+whatever variable rate it wants. The default value for
+this option is 0. \fI\%\-r\fP and \fI\%\-D\fP are mutually exclusive.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-rate\-period=<DURATION>
+Specifies the time period between creating connections.
+The period must be a positive number, representing the
+length of the period in time. This option is ignored if
+the rate option is not used. The default value for this
+option is 1s.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-D, \-\-duration=<DURATION>
+Specifies the main duration for the measurements in case
+of timing\-based benchmarking. \fI\%\-D\fP and \fI\%\-r\fP are mutually
+exclusive.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-warm\-up\-time=<DURATION>
+Specifies the time period before starting the actual
+measurements, in case of timing\-based benchmarking.
+Needs to provided along with \fI\%\-D\fP option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-T, \-\-connection\-active\-timeout=<DURATION>
+Specifies the maximum time that h2load is willing to
+keep a connection open, regardless of the activity on
+said connection. <DURATION> must be a positive integer,
+specifying the amount of time to wait. When no timeout
+value is set (either active or inactive), h2load will
+keep a connection open indefinitely, waiting for a
+response.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-N, \-\-connection\-inactivity\-timeout=<DURATION>
+Specifies the amount of time that h2load is willing to
+wait to see activity on a given connection. <DURATION>
+must be a positive integer, specifying the amount of
+time to wait. When no timeout value is set (either
+active or inactive), h2load will keep a connection open
+indefinitely, waiting for a response.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-timing\-script\-file=<PATH>
+Path of a file containing one or more lines separated by
+EOLs. Each script line is composed of two tab\-separated
+fields. The first field represents the time offset from
+the start of execution, expressed as a positive value of
+milliseconds with microsecond resolution. The second
+field represents the URI. This option will disable URIs
+getting from command\-line. If \(aq\-\(aq is given as <PATH>,
+script lines will be read from stdin. Script lines are
+used in order for each client. If \fI\%\-n\fP is given, it must
+be less than or equal to the number of script lines,
+larger values are clamped to the number of script lines.
+If \fI\%\-n\fP is not given, the number of requests will default
+to the number of script lines. The scheme, host and
+port defined in the first URI are used solely. Values
+contained in other URIs, if present, are ignored.
+Definition of a base URI overrides all scheme, host or
+port values. \fI\%\-\-timing\-script\-file\fP and \fI\%\-\-rps\fP are
+mutually exclusive.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-B, \-\-base\-uri=(<URI>|unix:<PATH>)
+Specify URI from which the scheme, host and port will be
+used for all requests. The base URI overrides all
+values defined either at the command line or inside
+input files. If argument starts with \(dqunix:\(dq, then the
+rest of the argument will be treated as UNIX domain
+socket path. The connection is made through that path
+instead of TCP. In this case, scheme is inferred from
+the first URI appeared in the command line or inside
+input files as usual.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-alpn\-list=<LIST>
+Comma delimited list of ALPN protocol identifier sorted
+in the order of preference. That means most desirable
+protocol comes first. The parameter must be delimited
+by a single comma only and any white spaces are treated
+as a part of protocol string.
+.sp
+Default: \fBh2,h2\-16,h2\-14,http/1.1\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-h1
+Short hand for \fI\%\-\-alpn\-list\fP=http/1.1
+\fI\%\-\-no\-tls\-proto\fP=http/1.1, which effectively force
+http/1.1 for both http and https URI.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-header\-table\-size=<SIZE>
+Specify decoder header table size.
+.sp
+Default: \fB4K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-encoder\-header\-table\-size=<SIZE>
+Specify encoder header table size. The decoder (server)
+specifies the maximum dynamic table size it accepts.
+Then the negotiated dynamic table size is the minimum of
+this option value and the value which server specified.
+.sp
+Default: \fB4K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-log\-file=<PATH>
+Write per\-request information to a file as tab\-separated
+columns: start time as microseconds since epoch; HTTP
+status code; microseconds until end of response. More
+columns may be added later. Rows are ordered by end\-of\-
+response time when using one worker thread, but may
+appear slightly out of order with multiple threads due
+to buffering. Status code is \-1 for failed streams.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-qlog\-file\-base=<PATH>
+Enable qlog output and specify base file name for qlogs.
+Qlog is emitted for each connection. For a given base
+name \(dqbase\(dq, each output file name becomes
+\(dqbase.M.N.sqlog\(dq where M is worker ID and N is client ID
+(e.g. \(dqbase.0.3.sqlog\(dq). Only effective in QUIC runs.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-connect\-to=<HOST>[:<PORT>]
+Host and port to connect instead of using the authority
+in <URI>.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-rps=<N>
+Specify request per second for each client. \fI\%\-\-rps\fP and
+\fI\%\-\-timing\-script\-file\fP are mutually exclusive.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-groups=<GROUPS>
+Specify the supported groups.
+.sp
+Default: \fBX25519:P\-256:P\-384:P\-521\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-udp\-gso
+Disable UDP GSO.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-max\-udp\-payload\-size=<SIZE>
+Specify the maximum outgoing UDP datagram payload size.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ktls
+Enable ktls.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-v, \-\-verbose
+Output debug information.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-version
+Display version information and exit.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-h, \-\-help
+Display this help and exit.
+.UNINDENT
+.sp
+The <SIZE> argument is an integer and an optional unit (e.g., 10K is
+10 * 1024). Units are K, M and G (powers of 1024).
+.sp
+The <DURATION> argument is an integer and an optional unit (e.g., 1s
+is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
+(hours, minutes, seconds and milliseconds, respectively). If a unit
+is omitted, a second is used as unit.
+.SH OUTPUT
+.INDENT 0.0
+.TP
+.B requests
+.INDENT 7.0
+.TP
+.B total
+The number of requests h2load was instructed to make.
+.TP
+.B started
+The number of requests h2load has started.
+.TP
+.B done
+The number of requests completed.
+.TP
+.B succeeded
+The number of requests completed successfully. Only HTTP status
+code 2xx or3xx are considered as success.
+.TP
+.B failed
+The number of requests failed, including HTTP level failures
+(non\-successful HTTP status code).
+.TP
+.B errored
+The number of requests failed, except for HTTP level failures.
+This is the subset of the number reported in \fBfailed\fP and most
+likely the network level failures or stream was reset by
+RST_STREAM.
+.TP
+.B timeout
+The number of requests whose connection timed out before they were
+completed. This is the subset of the number reported in
+\fBerrored\fP\&.
+.UNINDENT
+.TP
+.B status codes
+The number of status code h2load received.
+.TP
+.B traffic
+.INDENT 7.0
+.TP
+.B total
+The number of bytes received from the server \(dqon the wire\(dq. If
+requests were made via TLS, this value is the number of decrypted
+bytes.
+.TP
+.B headers
+The number of response header bytes from the server without
+decompression. The \fBspace savings\fP shows efficiency of header
+compression. Let \fBdecompressed(headers)\fP to the number of bytes
+used for header fields after decompression. The \fBspace savings\fP
+is calculated by (1 \- \fBheaders\fP / \fBdecompressed(headers)\fP) *
+100. For HTTP/1.1, this is usually 0.00%, since it does not have
+header compression. For HTTP/2, it shows some insightful numbers.
+.TP
+.B data
+The number of response body bytes received from the server.
+.UNINDENT
+.TP
+.B time for request
+.INDENT 7.0
+.TP
+.B min
+The minimum time taken for request and response.
+.TP
+.B max
+The maximum time taken for request and response.
+.TP
+.B mean
+The mean time taken for request and response.
+.TP
+.B sd
+The standard deviation of the time taken for request and response.
+.TP
+.B +/\- sd
+The fraction of the number of requests within standard deviation
+range (mean +/\- sd) against total number of successful requests.
+.UNINDENT
+.TP
+.B time for connect
+.INDENT 7.0
+.TP
+.B min
+The minimum time taken to connect to a server including TLS
+handshake.
+.TP
+.B max
+The maximum time taken to connect to a server including TLS
+handshake.
+.TP
+.B mean
+The mean time taken to connect to a server including TLS
+handshake.
+.TP
+.B sd
+The standard deviation of the time taken to connect to a server.
+.TP
+.B +/\- sd
+The fraction of the number of connections within standard
+deviation range (mean +/\- sd) against total number of successful
+connections.
+.UNINDENT
+.TP
+.B time for 1st byte (of (decrypted in case of TLS) application data)
+.INDENT 7.0
+.TP
+.B min
+The minimum time taken to get 1st byte from a server.
+.TP
+.B max
+The maximum time taken to get 1st byte from a server.
+.TP
+.B mean
+The mean time taken to get 1st byte from a server.
+.TP
+.B sd
+The standard deviation of the time taken to get 1st byte from a
+server.
+.TP
+.B +/\- sd
+The fraction of the number of connections within standard
+deviation range (mean +/\- sd) against total number of successful
+connections.
+.UNINDENT
+.TP
+.B req/s
+.INDENT 7.0
+.TP
+.B min
+The minimum request per second among all clients.
+.TP
+.B max
+The maximum request per second among all clients.
+.TP
+.B mean
+The mean request per second among all clients.
+.TP
+.B sd
+The standard deviation of request per second among all clients.
+server.
+.TP
+.B +/\- sd
+The fraction of the number of connections within standard
+deviation range (mean +/\- sd) against total number of successful
+connections.
+.UNINDENT
+.UNINDENT
+.SH FLOW CONTROL
+.sp
+h2load sets large flow control window by default, and effectively
+disables flow control to avoid under utilization of server
+performance. To set smaller flow control window, use \fI\%\-w\fP and
+\fI\%\-W\fP options. For example, use \fB\-w16 \-W16\fP to set default
+window size described in HTTP/2 protocol specification.
+.SH SEE ALSO
+.sp
+\fBnghttp(1)\fP, \fBnghttpd(1)\fP, \fBnghttpx(1)\fP
+.SH AUTHOR
+Tatsuhiro Tsujikawa
+.SH COPYRIGHT
+2012, 2015, 2016, Tatsuhiro Tsujikawa
+.\" Generated by docutils manpage writer.
+.
diff --git a/doc/h2load.1.rst b/doc/h2load.1.rst
new file mode 100644
index 0000000..85ed651
--- /dev/null
+++ b/doc/h2load.1.rst
@@ -0,0 +1,434 @@
+
+.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
+
+.. program:: h2load
+
+h2load(1)
+=========
+
+SYNOPSIS
+--------
+
+**h2load** [OPTIONS]... [URI]...
+
+DESCRIPTION
+-----------
+
+benchmarking tool for HTTP/2 server
+
+.. describe:: <URI>
+
+ Specify URI to access. Multiple URIs can be specified.
+ URIs are used in this order for each client. All URIs
+ are used, then first URI is used and then 2nd URI, and
+ so on. The scheme, host and port in the subsequent
+ URIs, if present, are ignored. Those in the first URI
+ are used solely. Definition of a base URI overrides all
+ scheme, host or port values.
+
+OPTIONS
+-------
+
+.. option:: -n, --requests=<N>
+
+ Number of requests across all clients. If it is used
+ with :option:`--timing-script-file` option, this option specifies
+ the number of requests each client performs rather than
+ the number of requests across all clients. This option
+ is ignored if timing-based benchmarking is enabled (see
+ :option:`--duration` option).
+
+ Default: ``1``
+
+.. option:: -c, --clients=<N>
+
+ Number of concurrent clients. With :option:`-r` option, this
+ specifies the maximum number of connections to be made.
+
+ Default: ``1``
+
+.. option:: -t, --threads=<N>
+
+ Number of native threads.
+
+ Default: ``1``
+
+.. option:: -i, --input-file=<PATH>
+
+ Path of a file with multiple URIs are separated by EOLs.
+ This option will disable URIs getting from command-line.
+ If '-' is given as <PATH>, URIs will be read from stdin.
+ URIs are used in this order for each client. All URIs
+ are used, then first URI is used and then 2nd URI, and
+ so on. The scheme, host and port in the subsequent
+ URIs, if present, are ignored. Those in the first URI
+ are used solely. Definition of a base URI overrides all
+ scheme, host or port values.
+
+.. option:: -m, --max-concurrent-streams=<N>
+
+ Max concurrent streams to issue per session. When
+ http/1.1 is used, this specifies the number of HTTP
+ pipelining requests in-flight.
+
+ Default: ``1``
+
+.. option:: -f, --max-frame-size=<SIZE>
+
+ Maximum frame size that the local endpoint is willing to
+ receive.
+
+ Default: ``16K``
+
+.. option:: -w, --window-bits=<N>
+
+ Sets the stream level initial window size to (2\*\*<N>)-1.
+ For QUIC, <N> is capped to 26 (roughly 64MiB).
+
+ Default: ``30``
+
+.. option:: -W, --connection-window-bits=<N>
+
+ Sets the connection level initial window size to
+ (2\*\*<N>)-1.
+
+ Default: ``30``
+
+.. option:: -H, --header=<HEADER>
+
+ Add/Override a header to the requests.
+
+.. option:: --ciphers=<SUITE>
+
+ Set allowed cipher list for TLSv1.2 or earlier. The
+ format of the string is described in OpenSSL ciphers(1).
+
+ Default: ``ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384``
+
+.. option:: --tls13-ciphers=<SUITE>
+
+ Set allowed cipher list for TLSv1.3. The format of the
+ string is described in OpenSSL ciphers(1).
+
+ Default: ``TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256``
+
+.. option:: -p, --no-tls-proto=<PROTOID>
+
+ Specify ALPN identifier of the protocol to be used when
+ accessing http URI without SSL/TLS.
+ Available protocols: h2c and http/1.1
+
+ Default: ``h2c``
+
+.. option:: -d, --data=<PATH>
+
+ Post FILE to server. The request method is changed to
+ POST. For http/1.1 connection, if :option:`-d` is used, the
+ maximum number of in-flight pipelined requests is set to
+ 1.
+
+.. option:: -r, --rate=<N>
+
+ Specifies the fixed rate at which connections are
+ created. The rate must be a positive integer,
+ representing the number of connections to be made per
+ rate period. The maximum number of connections to be
+ made is given in :option:`-c` option. This rate will be
+ distributed among threads as evenly as possible. For
+ example, with :option:`-t`\2 and :option:`-r`\4, each thread gets 2
+ connections per period. When the rate is 0, the program
+ will run as it normally does, creating connections at
+ whatever variable rate it wants. The default value for
+ this option is 0. :option:`-r` and :option:`\-D` are mutually exclusive.
+
+.. option:: --rate-period=<DURATION>
+
+ Specifies the time period between creating connections.
+ The period must be a positive number, representing the
+ length of the period in time. This option is ignored if
+ the rate option is not used. The default value for this
+ option is 1s.
+
+.. option:: -D, --duration=<DURATION>
+
+ Specifies the main duration for the measurements in case
+ of timing-based benchmarking. :option:`-D` and :option:`\-r` are mutually
+ exclusive.
+
+.. option:: --warm-up-time=<DURATION>
+
+ Specifies the time period before starting the actual
+ measurements, in case of timing-based benchmarking.
+ Needs to provided along with :option:`-D` option.
+
+.. option:: -T, --connection-active-timeout=<DURATION>
+
+ Specifies the maximum time that h2load is willing to
+ keep a connection open, regardless of the activity on
+ said connection. <DURATION> must be a positive integer,
+ specifying the amount of time to wait. When no timeout
+ value is set (either active or inactive), h2load will
+ keep a connection open indefinitely, waiting for a
+ response.
+
+.. option:: -N, --connection-inactivity-timeout=<DURATION>
+
+ Specifies the amount of time that h2load is willing to
+ wait to see activity on a given connection. <DURATION>
+ must be a positive integer, specifying the amount of
+ time to wait. When no timeout value is set (either
+ active or inactive), h2load will keep a connection open
+ indefinitely, waiting for a response.
+
+.. option:: --timing-script-file=<PATH>
+
+ Path of a file containing one or more lines separated by
+ EOLs. Each script line is composed of two tab-separated
+ fields. The first field represents the time offset from
+ the start of execution, expressed as a positive value of
+ milliseconds with microsecond resolution. The second
+ field represents the URI. This option will disable URIs
+ getting from command-line. If '-' is given as <PATH>,
+ script lines will be read from stdin. Script lines are
+ used in order for each client. If :option:`-n` is given, it must
+ be less than or equal to the number of script lines,
+ larger values are clamped to the number of script lines.
+ If :option:`-n` is not given, the number of requests will default
+ to the number of script lines. The scheme, host and
+ port defined in the first URI are used solely. Values
+ contained in other URIs, if present, are ignored.
+ Definition of a base URI overrides all scheme, host or
+ port values. :option:`--timing-script-file` and :option:`\--rps` are
+ mutually exclusive.
+
+.. option:: -B, --base-uri=(<URI>|unix:<PATH>)
+
+ Specify URI from which the scheme, host and port will be
+ used for all requests. The base URI overrides all
+ values defined either at the command line or inside
+ input files. If argument starts with "unix:", then the
+ rest of the argument will be treated as UNIX domain
+ socket path. The connection is made through that path
+ instead of TCP. In this case, scheme is inferred from
+ the first URI appeared in the command line or inside
+ input files as usual.
+
+.. option:: --alpn-list=<LIST>
+
+ Comma delimited list of ALPN protocol identifier sorted
+ in the order of preference. That means most desirable
+ protocol comes first. The parameter must be delimited
+ by a single comma only and any white spaces are treated
+ as a part of protocol string.
+
+ Default: ``h2,h2-16,h2-14,http/1.1``
+
+.. option:: --h1
+
+ Short hand for :option:`--alpn-list`\=http/1.1
+ :option:`--no-tls-proto`\=http/1.1, which effectively force
+ http/1.1 for both http and https URI.
+
+.. option:: --header-table-size=<SIZE>
+
+ Specify decoder header table size.
+
+ Default: ``4K``
+
+.. option:: --encoder-header-table-size=<SIZE>
+
+ Specify encoder header table size. The decoder (server)
+ specifies the maximum dynamic table size it accepts.
+ Then the negotiated dynamic table size is the minimum of
+ this option value and the value which server specified.
+
+ Default: ``4K``
+
+.. option:: --log-file=<PATH>
+
+ Write per-request information to a file as tab-separated
+ columns: start time as microseconds since epoch; HTTP
+ status code; microseconds until end of response. More
+ columns may be added later. Rows are ordered by end-of-
+ response time when using one worker thread, but may
+ appear slightly out of order with multiple threads due
+ to buffering. Status code is -1 for failed streams.
+
+.. option:: --qlog-file-base=<PATH>
+
+ Enable qlog output and specify base file name for qlogs.
+ Qlog is emitted for each connection. For a given base
+ name "base", each output file name becomes
+ "base.M.N.sqlog" where M is worker ID and N is client ID
+ (e.g. "base.0.3.sqlog"). Only effective in QUIC runs.
+
+.. option:: --connect-to=<HOST>[:<PORT>]
+
+ Host and port to connect instead of using the authority
+ in <URI>.
+
+.. option:: --rps=<N>
+
+ Specify request per second for each client. :option:`--rps` and
+ :option:`--timing-script-file` are mutually exclusive.
+
+.. option:: --groups=<GROUPS>
+
+ Specify the supported groups.
+
+ Default: ``X25519:P-256:P-384:P-521``
+
+.. option:: --no-udp-gso
+
+ Disable UDP GSO.
+
+.. option:: --max-udp-payload-size=<SIZE>
+
+ Specify the maximum outgoing UDP datagram payload size.
+
+.. option:: --ktls
+
+ Enable ktls.
+
+.. option:: -v, --verbose
+
+ Output debug information.
+
+.. option:: --version
+
+ Display version information and exit.
+
+.. option:: -h, --help
+
+ Display this help and exit.
+
+
+
+The <SIZE> argument is an integer and an optional unit (e.g., 10K is
+10 * 1024). Units are K, M and G (powers of 1024).
+
+The <DURATION> argument is an integer and an optional unit (e.g., 1s
+is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
+(hours, minutes, seconds and milliseconds, respectively). If a unit
+is omitted, a second is used as unit.
+
+.. _h2load-1-output:
+
+OUTPUT
+------
+
+requests
+ total
+ The number of requests h2load was instructed to make.
+ started
+ The number of requests h2load has started.
+ done
+ The number of requests completed.
+ succeeded
+ The number of requests completed successfully. Only HTTP status
+ code 2xx or3xx are considered as success.
+ failed
+ The number of requests failed, including HTTP level failures
+ (non-successful HTTP status code).
+ errored
+ The number of requests failed, except for HTTP level failures.
+ This is the subset of the number reported in ``failed`` and most
+ likely the network level failures or stream was reset by
+ RST_STREAM.
+ timeout
+ The number of requests whose connection timed out before they were
+ completed. This is the subset of the number reported in
+ ``errored``.
+
+status codes
+ The number of status code h2load received.
+
+traffic
+ total
+ The number of bytes received from the server "on the wire". If
+ requests were made via TLS, this value is the number of decrypted
+ bytes.
+ headers
+ The number of response header bytes from the server without
+ decompression. The ``space savings`` shows efficiency of header
+ compression. Let ``decompressed(headers)`` to the number of bytes
+ used for header fields after decompression. The ``space savings``
+ is calculated by (1 - ``headers`` / ``decompressed(headers)``) *
+ 100. For HTTP/1.1, this is usually 0.00%, since it does not have
+ header compression. For HTTP/2, it shows some insightful numbers.
+ data
+ The number of response body bytes received from the server.
+
+time for request
+ min
+ The minimum time taken for request and response.
+ max
+ The maximum time taken for request and response.
+ mean
+ The mean time taken for request and response.
+ sd
+ The standard deviation of the time taken for request and response.
+ +/- sd
+ The fraction of the number of requests within standard deviation
+ range (mean +/- sd) against total number of successful requests.
+
+time for connect
+ min
+ The minimum time taken to connect to a server including TLS
+ handshake.
+ max
+ The maximum time taken to connect to a server including TLS
+ handshake.
+ mean
+ The mean time taken to connect to a server including TLS
+ handshake.
+ sd
+ The standard deviation of the time taken to connect to a server.
+ +/- sd
+ The fraction of the number of connections within standard
+ deviation range (mean +/- sd) against total number of successful
+ connections.
+
+time for 1st byte (of (decrypted in case of TLS) application data)
+ min
+ The minimum time taken to get 1st byte from a server.
+ max
+ The maximum time taken to get 1st byte from a server.
+ mean
+ The mean time taken to get 1st byte from a server.
+ sd
+ The standard deviation of the time taken to get 1st byte from a
+ server.
+ +/- sd
+ The fraction of the number of connections within standard
+ deviation range (mean +/- sd) against total number of successful
+ connections.
+
+req/s
+ min
+ The minimum request per second among all clients.
+ max
+ The maximum request per second among all clients.
+ mean
+ The mean request per second among all clients.
+ sd
+ The standard deviation of request per second among all clients.
+ server.
+ +/- sd
+ The fraction of the number of connections within standard
+ deviation range (mean +/- sd) against total number of successful
+ connections.
+
+FLOW CONTROL
+------------
+
+h2load sets large flow control window by default, and effectively
+disables flow control to avoid under utilization of server
+performance. To set smaller flow control window, use :option:`-w` and
+:option:`-W` options. For example, use ``-w16 -W16`` to set default
+window size described in HTTP/2 protocol specification.
+
+SEE ALSO
+--------
+
+:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`
diff --git a/doc/h2load.h2r b/doc/h2load.h2r
new file mode 100644
index 0000000..50d9977
--- /dev/null
+++ b/doc/h2load.h2r
@@ -0,0 +1,120 @@
+.. _h2load-1-output:
+
+OUTPUT
+------
+
+requests
+ total
+ The number of requests h2load was instructed to make.
+ started
+ The number of requests h2load has started.
+ done
+ The number of requests completed.
+ succeeded
+ The number of requests completed successfully. Only HTTP status
+ code 2xx or3xx are considered as success.
+ failed
+ The number of requests failed, including HTTP level failures
+ (non-successful HTTP status code).
+ errored
+ The number of requests failed, except for HTTP level failures.
+ This is the subset of the number reported in ``failed`` and most
+ likely the network level failures or stream was reset by
+ RST_STREAM.
+ timeout
+ The number of requests whose connection timed out before they were
+ completed. This is the subset of the number reported in
+ ``errored``.
+
+status codes
+ The number of status code h2load received.
+
+traffic
+ total
+ The number of bytes received from the server "on the wire". If
+ requests were made via TLS, this value is the number of decrypted
+ bytes.
+ headers
+ The number of response header bytes from the server without
+ decompression. The ``space savings`` shows efficiency of header
+ compression. Let ``decompressed(headers)`` to the number of bytes
+ used for header fields after decompression. The ``space savings``
+ is calculated by (1 - ``headers`` / ``decompressed(headers)``) *
+ 100. For HTTP/1.1, this is usually 0.00%, since it does not have
+ header compression. For HTTP/2, it shows some insightful numbers.
+ data
+ The number of response body bytes received from the server.
+
+time for request
+ min
+ The minimum time taken for request and response.
+ max
+ The maximum time taken for request and response.
+ mean
+ The mean time taken for request and response.
+ sd
+ The standard deviation of the time taken for request and response.
+ +/- sd
+ The fraction of the number of requests within standard deviation
+ range (mean +/- sd) against total number of successful requests.
+
+time for connect
+ min
+ The minimum time taken to connect to a server including TLS
+ handshake.
+ max
+ The maximum time taken to connect to a server including TLS
+ handshake.
+ mean
+ The mean time taken to connect to a server including TLS
+ handshake.
+ sd
+ The standard deviation of the time taken to connect to a server.
+ +/- sd
+ The fraction of the number of connections within standard
+ deviation range (mean +/- sd) against total number of successful
+ connections.
+
+time for 1st byte (of (decrypted in case of TLS) application data)
+ min
+ The minimum time taken to get 1st byte from a server.
+ max
+ The maximum time taken to get 1st byte from a server.
+ mean
+ The mean time taken to get 1st byte from a server.
+ sd
+ The standard deviation of the time taken to get 1st byte from a
+ server.
+ +/- sd
+ The fraction of the number of connections within standard
+ deviation range (mean +/- sd) against total number of successful
+ connections.
+
+req/s
+ min
+ The minimum request per second among all clients.
+ max
+ The maximum request per second among all clients.
+ mean
+ The mean request per second among all clients.
+ sd
+ The standard deviation of request per second among all clients.
+ server.
+ +/- sd
+ The fraction of the number of connections within standard
+ deviation range (mean +/- sd) against total number of successful
+ connections.
+
+FLOW CONTROL
+------------
+
+h2load sets large flow control window by default, and effectively
+disables flow control to avoid under utilization of server
+performance. To set smaller flow control window, use :option:`-w` and
+:option:`-W` options. For example, use ``-w16 -W16`` to set default
+window size described in HTTP/2 protocol specification.
+
+SEE ALSO
+--------
+
+:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`
diff --git a/doc/index.rst.in b/doc/index.rst.in
new file mode 100644
index 0000000..2a49369
--- /dev/null
+++ b/doc/index.rst.in
@@ -0,0 +1 @@
+.. include:: @top_srcdir@/doc/sources/index.rst
diff --git a/doc/make.bat b/doc/make.bat
new file mode 100644
index 0000000..2e0500d
--- /dev/null
+++ b/doc/make.bat
@@ -0,0 +1,170 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\nghttp2.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\nghttp2.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/doc/mkapiref.py b/doc/mkapiref.py
new file mode 100755
index 0000000..df59fbc
--- /dev/null
+++ b/doc/mkapiref.py
@@ -0,0 +1,343 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# nghttp2 - HTTP/2 C Library
+#
+# Copyright (c) 2020 nghttp2 contributors
+# Copyright (c) 2020 ngtcp2 contributors
+# Copyright (c) 2012 Tatsuhiro Tsujikawa
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+# Generates API reference from C source code.
+
+import re, sys, argparse, os.path
+
+class FunctionDoc:
+ def __init__(self, name, content, domain, filename):
+ self.name = name
+ self.content = content
+ self.domain = domain
+ if self.domain == 'function':
+ self.funcname = re.search(r'(nghttp2_[^ )]+)\(', self.name).group(1)
+ self.filename = filename
+
+ def write(self, out):
+ out.write('.. {}:: {}\n'.format(self.domain, self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+
+class StructDoc:
+ def __init__(self, name, content, members, member_domain):
+ self.name = name
+ self.content = content
+ self.members = members
+ self.member_domain = member_domain
+
+ def write(self, out):
+ if self.name:
+ out.write('.. type:: {}\n'.format(self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+ out.write('\n')
+ for name, content in self.members:
+ out.write(' .. {}:: {}\n'.format(self.member_domain, name))
+ out.write('\n')
+ for line in content:
+ out.write(' {}\n'.format(line))
+ out.write('\n')
+
+class EnumDoc:
+ def __init__(self, name, content, members):
+ self.name = name
+ self.content = content
+ self.members = members
+
+ def write(self, out):
+ if self.name:
+ out.write('.. type:: {}\n'.format(self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+ out.write('\n')
+ for name, content in self.members:
+ out.write(' .. enum:: {}\n'.format(name))
+ out.write('\n')
+ for line in content:
+ out.write(' {}\n'.format(line))
+ out.write('\n')
+
+class MacroDoc:
+ def __init__(self, name, content):
+ self.name = name
+ self.content = content
+
+ def write(self, out):
+ out.write('''.. macro:: {}\n'''.format(self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+
+class MacroSectionDoc:
+ def __init__(self, content):
+ self.content = content
+
+ def write(self, out):
+ out.write('\n')
+ c = ' '.join(self.content).strip()
+ out.write(c)
+ out.write('\n')
+ out.write('-' * len(c))
+ out.write('\n\n')
+
+class TypedefDoc:
+ def __init__(self, name, content):
+ self.name = name
+ self.content = content
+
+ def write(self, out):
+ out.write('''.. type:: {}\n'''.format(self.name))
+ out.write('\n')
+ for line in self.content:
+ out.write(' {}\n'.format(line))
+
+def make_api_ref(infile):
+ macros = []
+ enums = []
+ types = []
+ functions = []
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ elif line == '/**\n':
+ line = infile.readline()
+ doctype = line.split()[1]
+ if doctype == '@function':
+ functions.append(process_function('function', infile))
+ elif doctype == '@functypedef':
+ types.append(process_function('type', infile))
+ elif doctype == '@struct' or doctype == '@union':
+ types.append(process_struct(infile))
+ elif doctype == '@enum':
+ enums.append(process_enum(infile))
+ elif doctype == '@macro':
+ macros.append(process_macro(infile))
+ elif doctype == '@macrosection':
+ macros.append(process_macrosection(infile))
+ elif doctype == '@typedef':
+ types.append(process_typedef(infile))
+ return macros, enums, types, functions
+
+def output(
+ title, indexfile, macrosfile, enumsfile, typesfile, funcsdir,
+ macros, enums, types, functions):
+ indexfile.write('''
+{title}
+{titledecoration}
+
+.. toctree::
+ :maxdepth: 1
+
+ {macros}
+ {enums}
+ {types}
+'''.format(
+ title=title, titledecoration='='*len(title),
+ macros=os.path.splitext(os.path.basename(macrosfile.name))[0],
+ enums=os.path.splitext(os.path.basename(enumsfile.name))[0],
+ types=os.path.splitext(os.path.basename(typesfile.name))[0],
+))
+
+ for doc in functions:
+ indexfile.write(' {}\n'.format(doc.funcname))
+
+ macrosfile.write('''
+Macros
+======
+''')
+ for doc in macros:
+ doc.write(macrosfile)
+
+ enumsfile.write('''
+Enums
+=====
+''')
+ for doc in enums:
+ doc.write(enumsfile)
+
+ typesfile.write('''
+Types (structs, unions and typedefs)
+====================================
+''')
+ for doc in types:
+ doc.write(typesfile)
+
+ for doc in functions:
+ with open(os.path.join(funcsdir, doc.funcname + '.rst'), 'w') as f:
+ f.write('''
+{funcname}
+{secul}
+
+Synopsis
+--------
+
+*#include <nghttp2/{filename}>*
+
+'''.format(funcname=doc.funcname, secul='='*len(doc.funcname),
+ filename=doc.filename))
+ doc.write(f)
+
+def process_macro(infile):
+ content = read_content(infile)
+ line = infile.readline()
+ macro_name = line.split()[1]
+ return MacroDoc(macro_name, content)
+
+def process_macrosection(infile):
+ content = read_content(infile)
+ return MacroSectionDoc(content)
+
+def process_typedef(infile):
+ content = read_content(infile)
+ typedef = infile.readline()
+ typedef = re.sub(r';\n$', '', typedef)
+ typedef = re.sub(r'typedef ', '', typedef)
+ return TypedefDoc(typedef, content)
+
+def process_enum(infile):
+ members = []
+ enum_name = None
+ content = read_content(infile)
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ elif re.match(r'\s*/\*\*\n', line):
+ member_content = read_content(infile)
+ line = infile.readline()
+ items = line.split()
+ member_name = items[0].rstrip(',')
+ if len(items) >= 3:
+ member_content.insert(0, '(``{}``) '\
+ .format(' '.join(items[2:]).rstrip(',')))
+ members.append((member_name, member_content))
+ elif line.startswith('}'):
+ enum_name = line.rstrip().split()[1]
+ enum_name = re.sub(r';$', '', enum_name)
+ break
+ return EnumDoc(enum_name, content, members)
+
+def process_struct(infile):
+ members = []
+ struct_name = None
+ content = read_content(infile)
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ elif re.match(r'\s*/\*\*\n', line):
+ member_content = read_content(infile)
+ line = infile.readline()
+ member_name = line.rstrip().rstrip(';')
+ members.append((member_name, member_content))
+ elif line.startswith('}') or\
+ (line.startswith('typedef ') and line.endswith(';\n')):
+ if line.startswith('}'):
+ index = 1
+ else:
+ index = 3
+ struct_name = line.rstrip().split()[index]
+ struct_name = re.sub(r';$', '', struct_name)
+ break
+ return StructDoc(struct_name, content, members, 'member')
+
+def process_function(domain, infile):
+ content = read_content(infile)
+ func_proto = []
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ elif line == '\n':
+ break
+ else:
+ func_proto.append(line)
+ func_proto = ''.join(func_proto)
+ func_proto = re.sub(r';\n$', '', func_proto)
+ func_proto = re.sub(r'\s+', ' ', func_proto)
+ func_proto = re.sub(r'NGHTTP2_EXTERN ', '', func_proto)
+ func_proto = re.sub(r'typedef ', '', func_proto)
+ filename = os.path.basename(infile.name)
+ return FunctionDoc(func_proto, content, domain, filename)
+
+def read_content(infile):
+ content = []
+ while True:
+ line = infile.readline()
+ if not line:
+ break
+ if re.match(r'\s*\*/\n', line):
+ break
+ else:
+ content.append(transform_content(line.rstrip()))
+ return content
+
+def arg_repl(matchobj):
+ return '*{}*'.format(matchobj.group(1).replace('*', '\\*'))
+
+def transform_content(content):
+ content = re.sub(r'^\s+\* ?', '', content)
+ content = re.sub(r'\|([^\s|]+)\|', arg_repl, content)
+ return content
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description="Generate API reference")
+ parser.add_argument('--title', default='API Reference',
+ help='title of index page')
+ parser.add_argument('index', type=argparse.FileType('w'),
+ help='index output file')
+ parser.add_argument('macros', type=argparse.FileType('w'),
+ help='macros section output file. The filename should be macros.rst')
+ parser.add_argument('enums', type=argparse.FileType('w'),
+ help='enums section output file. The filename should be enums.rst')
+ parser.add_argument('types', type=argparse.FileType('w'),
+ help='types section output file. The filename should be types.rst')
+ parser.add_argument('funcsdir',
+ help='functions doc output dir')
+ parser.add_argument('files', nargs='+', type=argparse.FileType('r'),
+ help='source file')
+ args = parser.parse_args()
+ macros = []
+ enums = []
+ types = []
+ funcs = []
+ for infile in args.files:
+ m, e, t, f = make_api_ref(infile)
+ macros.extend(m)
+ enums.extend(e)
+ types.extend(t)
+ funcs.extend(f)
+ funcs.sort(key=lambda x: x.funcname)
+ output(
+ args.title,
+ args.index, args.macros, args.enums, args.types, args.funcsdir,
+ macros, enums, types, funcs)
diff --git a/doc/nghttp.1 b/doc/nghttp.1
new file mode 100644
index 0000000..332d9c6
--- /dev/null
+++ b/doc/nghttp.1
@@ -0,0 +1,336 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "NGHTTP" "1" "Jan 21, 2024" "1.59.0" "nghttp2"
+.SH NAME
+nghttp \- HTTP/2 client
+.SH SYNOPSIS
+.sp
+\fBnghttp\fP [OPTIONS]... <URI>...
+.SH DESCRIPTION
+.sp
+HTTP/2 client
+.INDENT 0.0
+.TP
+.B <URI>
+Specify URI to access.
+.UNINDENT
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B \-v, \-\-verbose
+Print debug information such as reception and
+transmission of frames and name/value pairs. Specifying
+this option multiple times increases verbosity.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-n, \-\-null\-out
+Discard downloaded data.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-O, \-\-remote\-name
+Save download data in the current directory. The
+filename is derived from URI. If URI ends with \(aq\fI/\fP\(aq,
+\(aqindex.html\(aq is used as a filename. Not implemented
+yet.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-t, \-\-timeout=<DURATION>
+Timeout each request after <DURATION>. Set 0 to disable
+timeout.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-w, \-\-window\-bits=<N>
+Sets the stream level initial window size to 2**<N>\-1.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-W, \-\-connection\-window\-bits=<N>
+Sets the connection level initial window size to
+2**<N>\-1.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-a, \-\-get\-assets
+Download assets such as stylesheets, images and script
+files linked from the downloaded resource. Only links
+whose origins are the same with the linking resource
+will be downloaded. nghttp prioritizes resources using
+HTTP/2 dependency based priority. The priority order,
+from highest to lowest, is html itself, css, javascript
+and images.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-s, \-\-stat
+Print statistics.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-H, \-\-header=<HEADER>
+Add a header to the requests. Example: \fI\%\-H\fP\(aq:method: PUT\(aq
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-trailer=<HEADER>
+Add a trailer header to the requests. <HEADER> must not
+include pseudo header field (header field name starting
+with \(aq:\(aq). To send trailer, one must use \fI\%\-d\fP option to
+send request body. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-cert=<CERT>
+Use the specified client certificate file. The file
+must be in PEM format.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-key=<KEY>
+Use the client private key file. The file must be in
+PEM format.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-d, \-\-data=<PATH>
+Post FILE to server. If \(aq\-\(aq is given, data will be read
+from stdin.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-m, \-\-multiply=<N>
+Request each URI <N> times. By default, same URI is not
+requested twice. This option disables it too.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-u, \-\-upgrade
+Perform HTTP Upgrade for HTTP/2. This option is ignored
+if the request URI has https scheme. If \fI\%\-d\fP is used, the
+HTTP upgrade request is performed with OPTIONS method.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-p, \-\-weight=<WEIGHT>
+Sets weight of given URI. This option can be used
+multiple times, and N\-th \fI\%\-p\fP option sets weight of N\-th
+URI in the command line. If the number of \fI\%\-p\fP option is
+less than the number of URI, the last \fI\%\-p\fP option value is
+repeated. If there is no \fI\%\-p\fP option, default weight, 16,
+is assumed. The valid value range is
+[1, 256], inclusive.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-M, \-\-peer\-max\-concurrent\-streams=<N>
+Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value of
+remote endpoint as if it is received in SETTINGS frame.
+.sp
+Default: \fB100\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-c, \-\-header\-table\-size=<SIZE>
+Specify decoder header table size. If this option is
+used multiple times, and the minimum value among the
+given values except for last one is strictly less than
+the last value, that minimum value is set in SETTINGS
+frame payload before the last value, to simulate
+multiple header table size change.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-encoder\-header\-table\-size=<SIZE>
+Specify encoder header table size. The decoder (server)
+specifies the maximum dynamic table size it accepts.
+Then the negotiated dynamic table size is the minimum of
+this option value and the value which server specified.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-b, \-\-padding=<N>
+Add at most <N> bytes to a frame payload as padding.
+Specify 0 to disable padding.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-r, \-\-har=<PATH>
+Output HTTP transactions <PATH> in HAR format. If \(aq\-\(aq
+is given, data is written to stdout.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-color
+Force colored log output.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-continuation
+Send large header to test CONTINUATION.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-content\-length
+Don\(aqt send content\-length header field.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-dep
+Don\(aqt send dependency based priority hint to server.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-hexdump
+Display the incoming traffic in hexadecimal (Canonical
+hex+ASCII display). If SSL/TLS is used, decrypted data
+are used.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-push
+Disable server push.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-max\-concurrent\-streams=<N>
+The number of concurrent pushed streams this client
+accepts.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-expect\-continue
+Perform an Expect/Continue handshake: wait to send DATA
+(up to a short timeout) until the server sends a 100
+Continue interim response. This option is ignored unless
+combined with the \fI\%\-d\fP option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-y, \-\-no\-verify\-peer
+Suppress warning on server certificate verification
+failure.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ktls
+Enable ktls.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-rfc7540\-pri
+Disable RFC7540 priorities.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-version
+Display version information and exit.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-h, \-\-help
+Display this help and exit.
+.UNINDENT
+.sp
+The <SIZE> argument is an integer and an optional unit (e.g., 10K is
+10 * 1024). Units are K, M and G (powers of 1024).
+.sp
+The <DURATION> argument is an integer and an optional unit (e.g., 1s
+is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
+(hours, minutes, seconds and milliseconds, respectively). If a unit
+is omitted, a second is used as unit.
+.SH DEPENDENCY BASED PRIORITY
+.sp
+nghttp sends priority hints to server by default unless
+\fI\%\-\-no\-dep\fP is used. nghttp mimics the way Firefox employs to
+manages dependency using idle streams. We follows the behaviour of
+Firefox Nightly as of April, 2015, and nghttp\(aqs behaviour is very
+static and could be different from Firefox in detail. But reproducing
+the same behaviour of Firefox is not our goal. The goal is provide
+the easy way to test out the dependency priority in server
+implementation.
+.sp
+When connection is established, nghttp sends 5 PRIORITY frames to idle
+streams 3, 5, 7, 9 and 11 to create \(dqanchor\(dq nodes in dependency
+tree:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+ +\-\-\-\-\-+
+ |id=0 |
+ +\-\-\-\-\-+
+ ^ ^ ^
+ w=201 / | \e w=1
+ / | \e
+ / w=101| \e
+ +\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
+ |id=3 | |id=5 | |id=7 |
+ +\-\-\-\-\-+ +\-\-\-\-\-+ +\-\-\-\-\-+
+ ^ ^
+w=1 | w=1 |
+ | |
+ +\-\-\-\-\-+ +\-\-\-\-\-+
+ |id=11| |id=9 |
+ +\-\-\-\-\-+ +\-\-\-\-\-+
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+In the above figure, \fBid\fP means stream ID, and \fBw\fP means weight.
+The stream 0 is non\-existence stream, and forms the root of the tree.
+The stream 7 and 9 are not used for now.
+.sp
+The URIs given in the command\-line depend on stream 11 with the weight
+given in \fI\%\-p\fP option, which defaults to 16.
+.sp
+If \fI\%\-a\fP option is used, nghttp parses the resource pointed by
+URI given in command\-line as html, and extracts resource links from
+it. When requesting those resources, nghttp uses dependency according
+to its resource type.
+.sp
+For CSS, and Javascript files inside \(dqhead\(dq element, they depend on
+stream 3 with the weight 2. The Javascript files outside \(dqhead\(dq
+element depend on stream 5 with the weight 2. The mages depend on
+stream 11 with the weight 12. The other resources (e.g., icon) depend
+on stream 11 with the weight 2.
+.SH SEE ALSO
+.sp
+\fBnghttpd(1)\fP, \fBnghttpx(1)\fP, \fBh2load(1)\fP
+.SH AUTHOR
+Tatsuhiro Tsujikawa
+.SH COPYRIGHT
+2012, 2015, 2016, Tatsuhiro Tsujikawa
+.\" Generated by docutils manpage writer.
+.
diff --git a/doc/nghttp.1.rst b/doc/nghttp.1.rst
new file mode 100644
index 0000000..e10f3ee
--- /dev/null
+++ b/doc/nghttp.1.rst
@@ -0,0 +1,276 @@
+
+.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
+
+.. program:: nghttp
+
+nghttp(1)
+=========
+
+SYNOPSIS
+--------
+
+**nghttp** [OPTIONS]... <URI>...
+
+DESCRIPTION
+-----------
+
+HTTP/2 client
+
+.. describe:: <URI>
+
+ Specify URI to access.
+
+OPTIONS
+-------
+
+.. option:: -v, --verbose
+
+ Print debug information such as reception and
+ transmission of frames and name/value pairs. Specifying
+ this option multiple times increases verbosity.
+
+.. option:: -n, --null-out
+
+ Discard downloaded data.
+
+.. option:: -O, --remote-name
+
+ Save download data in the current directory. The
+ filename is derived from URI. If URI ends with '*/*',
+ 'index.html' is used as a filename. Not implemented
+ yet.
+
+.. option:: -t, --timeout=<DURATION>
+
+ Timeout each request after <DURATION>. Set 0 to disable
+ timeout.
+
+.. option:: -w, --window-bits=<N>
+
+ Sets the stream level initial window size to 2\*\*<N>-1.
+
+.. option:: -W, --connection-window-bits=<N>
+
+ Sets the connection level initial window size to
+ 2\*\*<N>-1.
+
+.. option:: -a, --get-assets
+
+ Download assets such as stylesheets, images and script
+ files linked from the downloaded resource. Only links
+ whose origins are the same with the linking resource
+ will be downloaded. nghttp prioritizes resources using
+ HTTP/2 dependency based priority. The priority order,
+ from highest to lowest, is html itself, css, javascript
+ and images.
+
+.. option:: -s, --stat
+
+ Print statistics.
+
+.. option:: -H, --header=<HEADER>
+
+ Add a header to the requests. Example: :option:`-H`\':method: PUT'
+
+.. option:: --trailer=<HEADER>
+
+ Add a trailer header to the requests. <HEADER> must not
+ include pseudo header field (header field name starting
+ with ':'). To send trailer, one must use :option:`-d` option to
+ send request body. Example: :option:`--trailer` 'foo: bar'.
+
+.. option:: --cert=<CERT>
+
+ Use the specified client certificate file. The file
+ must be in PEM format.
+
+.. option:: --key=<KEY>
+
+ Use the client private key file. The file must be in
+ PEM format.
+
+.. option:: -d, --data=<PATH>
+
+ Post FILE to server. If '-' is given, data will be read
+ from stdin.
+
+.. option:: -m, --multiply=<N>
+
+ Request each URI <N> times. By default, same URI is not
+ requested twice. This option disables it too.
+
+.. option:: -u, --upgrade
+
+ Perform HTTP Upgrade for HTTP/2. This option is ignored
+ if the request URI has https scheme. If :option:`-d` is used, the
+ HTTP upgrade request is performed with OPTIONS method.
+
+.. option:: -p, --weight=<WEIGHT>
+
+ Sets weight of given URI. This option can be used
+ multiple times, and N-th :option:`-p` option sets weight of N-th
+ URI in the command line. If the number of :option:`-p` option is
+ less than the number of URI, the last :option:`-p` option value is
+ repeated. If there is no :option:`-p` option, default weight, 16,
+ is assumed. The valid value range is
+ [1, 256], inclusive.
+
+.. option:: -M, --peer-max-concurrent-streams=<N>
+
+ Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value of
+ remote endpoint as if it is received in SETTINGS frame.
+
+ Default: ``100``
+
+.. option:: -c, --header-table-size=<SIZE>
+
+ Specify decoder header table size. If this option is
+ used multiple times, and the minimum value among the
+ given values except for last one is strictly less than
+ the last value, that minimum value is set in SETTINGS
+ frame payload before the last value, to simulate
+ multiple header table size change.
+
+.. option:: --encoder-header-table-size=<SIZE>
+
+ Specify encoder header table size. The decoder (server)
+ specifies the maximum dynamic table size it accepts.
+ Then the negotiated dynamic table size is the minimum of
+ this option value and the value which server specified.
+
+.. option:: -b, --padding=<N>
+
+ Add at most <N> bytes to a frame payload as padding.
+ Specify 0 to disable padding.
+
+.. option:: -r, --har=<PATH>
+
+ Output HTTP transactions <PATH> in HAR format. If '-'
+ is given, data is written to stdout.
+
+.. option:: --color
+
+ Force colored log output.
+
+.. option:: --continuation
+
+ Send large header to test CONTINUATION.
+
+.. option:: --no-content-length
+
+ Don't send content-length header field.
+
+.. option:: --no-dep
+
+ Don't send dependency based priority hint to server.
+
+.. option:: --hexdump
+
+ Display the incoming traffic in hexadecimal (Canonical
+ hex+ASCII display). If SSL/TLS is used, decrypted data
+ are used.
+
+.. option:: --no-push
+
+ Disable server push.
+
+.. option:: --max-concurrent-streams=<N>
+
+ The number of concurrent pushed streams this client
+ accepts.
+
+.. option:: --expect-continue
+
+ Perform an Expect/Continue handshake: wait to send DATA
+ (up to a short timeout) until the server sends a 100
+ Continue interim response. This option is ignored unless
+ combined with the :option:`-d` option.
+
+.. option:: -y, --no-verify-peer
+
+ Suppress warning on server certificate verification
+ failure.
+
+.. option:: --ktls
+
+ Enable ktls.
+
+.. option:: --no-rfc7540-pri
+
+ Disable RFC7540 priorities.
+
+.. option:: --version
+
+ Display version information and exit.
+
+.. option:: -h, --help
+
+ Display this help and exit.
+
+
+
+The <SIZE> argument is an integer and an optional unit (e.g., 10K is
+10 * 1024). Units are K, M and G (powers of 1024).
+
+The <DURATION> argument is an integer and an optional unit (e.g., 1s
+is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
+(hours, minutes, seconds and milliseconds, respectively). If a unit
+is omitted, a second is used as unit.
+
+DEPENDENCY BASED PRIORITY
+-------------------------
+
+nghttp sends priority hints to server by default unless
+:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
+manages dependency using idle streams. We follows the behaviour of
+Firefox Nightly as of April, 2015, and nghttp's behaviour is very
+static and could be different from Firefox in detail. But reproducing
+the same behaviour of Firefox is not our goal. The goal is provide
+the easy way to test out the dependency priority in server
+implementation.
+
+When connection is established, nghttp sends 5 PRIORITY frames to idle
+streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
+tree:
+
+.. code-block:: text
+
+ +-----+
+ |id=0 |
+ +-----+
+ ^ ^ ^
+ w=201 / | \ w=1
+ / | \
+ / w=101| \
+ +-----+ +-----+ +-----+
+ |id=3 | |id=5 | |id=7 |
+ +-----+ +-----+ +-----+
+ ^ ^
+ w=1 | w=1 |
+ | |
+ +-----+ +-----+
+ |id=11| |id=9 |
+ +-----+ +-----+
+
+In the above figure, ``id`` means stream ID, and ``w`` means weight.
+The stream 0 is non-existence stream, and forms the root of the tree.
+The stream 7 and 9 are not used for now.
+
+The URIs given in the command-line depend on stream 11 with the weight
+given in :option:`-p` option, which defaults to 16.
+
+If :option:`-a` option is used, nghttp parses the resource pointed by
+URI given in command-line as html, and extracts resource links from
+it. When requesting those resources, nghttp uses dependency according
+to its resource type.
+
+For CSS, and Javascript files inside "head" element, they depend on
+stream 3 with the weight 2. The Javascript files outside "head"
+element depend on stream 5 with the weight 2. The mages depend on
+stream 11 with the weight 12. The other resources (e.g., icon) depend
+on stream 11 with the weight 2.
+
+SEE ALSO
+--------
+
+:manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`
diff --git a/doc/nghttp.h2r b/doc/nghttp.h2r
new file mode 100644
index 0000000..9d2a90e
--- /dev/null
+++ b/doc/nghttp.h2r
@@ -0,0 +1,57 @@
+DEPENDENCY BASED PRIORITY
+-------------------------
+
+nghttp sends priority hints to server by default unless
+:option:`--no-dep` is used. nghttp mimics the way Firefox employs to
+manages dependency using idle streams. We follows the behaviour of
+Firefox Nightly as of April, 2015, and nghttp's behaviour is very
+static and could be different from Firefox in detail. But reproducing
+the same behaviour of Firefox is not our goal. The goal is provide
+the easy way to test out the dependency priority in server
+implementation.
+
+When connection is established, nghttp sends 5 PRIORITY frames to idle
+streams 3, 5, 7, 9 and 11 to create "anchor" nodes in dependency
+tree:
+
+.. code-block:: text
+
+ +-----+
+ |id=0 |
+ +-----+
+ ^ ^ ^
+ w=201 / | \ w=1
+ / | \
+ / w=101| \
+ +-----+ +-----+ +-----+
+ |id=3 | |id=5 | |id=7 |
+ +-----+ +-----+ +-----+
+ ^ ^
+ w=1 | w=1 |
+ | |
+ +-----+ +-----+
+ |id=11| |id=9 |
+ +-----+ +-----+
+
+In the above figure, ``id`` means stream ID, and ``w`` means weight.
+The stream 0 is non-existence stream, and forms the root of the tree.
+The stream 7 and 9 are not used for now.
+
+The URIs given in the command-line depend on stream 11 with the weight
+given in :option:`-p` option, which defaults to 16.
+
+If :option:`-a` option is used, nghttp parses the resource pointed by
+URI given in command-line as html, and extracts resource links from
+it. When requesting those resources, nghttp uses dependency according
+to its resource type.
+
+For CSS, and Javascript files inside "head" element, they depend on
+stream 3 with the weight 2. The Javascript files outside "head"
+element depend on stream 5 with the weight 2. The mages depend on
+stream 11 with the weight 12. The other resources (e.g., icon) depend
+on stream 11 with the weight 2.
+
+SEE ALSO
+--------
+
+:manpage:`nghttpd(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`
diff --git a/doc/nghttp2.h.rst.in b/doc/nghttp2.h.rst.in
new file mode 100644
index 0000000..29e641d
--- /dev/null
+++ b/doc/nghttp2.h.rst.in
@@ -0,0 +1,4 @@
+nghttp2.h
+=========
+
+.. literalinclude:: @top_srcdir@/lib/includes/nghttp2/nghttp2.h
diff --git a/doc/nghttp2ver.h.rst.in b/doc/nghttp2ver.h.rst.in
new file mode 100644
index 0000000..c6aa779
--- /dev/null
+++ b/doc/nghttp2ver.h.rst.in
@@ -0,0 +1,4 @@
+nghttp2ver.h
+============
+
+.. literalinclude:: @top_builddir@/lib/includes/nghttp2/nghttp2ver.h
diff --git a/doc/nghttpd.1 b/doc/nghttpd.1
new file mode 100644
index 0000000..219a365
--- /dev/null
+++ b/doc/nghttpd.1
@@ -0,0 +1,236 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "NGHTTPD" "1" "Jan 21, 2024" "1.59.0" "nghttp2"
+.SH NAME
+nghttpd \- HTTP/2 server
+.SH SYNOPSIS
+.sp
+\fBnghttpd\fP [OPTION]... <PORT> [<PRIVATE_KEY> <CERT>]
+.SH DESCRIPTION
+.sp
+HTTP/2 server
+.INDENT 0.0
+.TP
+.B <PORT>
+Specify listening port number.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B <PRIVATE_KEY>
+Set path to server\(aqs private key. Required unless
+\fI\%\-\-no\-tls\fP is specified.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B <CERT>
+Set path to server\(aqs certificate. Required unless
+\fI\%\-\-no\-tls\fP is specified.
+.UNINDENT
+.SH OPTIONS
+.INDENT 0.0
+.TP
+.B \-a, \-\-address=<ADDR>
+The address to bind to. If not specified the default IP
+address determined by getaddrinfo is used.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-D, \-\-daemon
+Run in a background. If \fI\%\-D\fP is used, the current working
+directory is changed to \(aq\fI/\fP\(aq. Therefore if this option
+is used, \fI\%\-d\fP option must be specified.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-V, \-\-verify\-client
+The server sends a client certificate request. If the
+client did not return a certificate, the handshake is
+terminated. Currently, this option just requests a
+client certificate and does not verify it.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-d, \-\-htdocs=<PATH>
+Specify document root. If this option is not specified,
+the document root is the current working directory.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-v, \-\-verbose
+Print debug information such as reception/ transmission
+of frames and name/value pairs.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-tls
+Disable SSL/TLS.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-c, \-\-header\-table\-size=<SIZE>
+Specify decoder header table size.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-encoder\-header\-table\-size=<SIZE>
+Specify encoder header table size. The decoder (client)
+specifies the maximum dynamic table size it accepts.
+Then the negotiated dynamic table size is the minimum of
+this option value and the value which client specified.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-color
+Force colored log output.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-p, \-\-push=<PATH>=<PUSH_PATH,...>
+Push resources <PUSH_PATH>s when <PATH> is requested.
+This option can be used repeatedly to specify multiple
+push configurations. <PATH> and <PUSH_PATH>s are
+relative to document root. See \fI\%\-\-htdocs\fP option.
+Example: \fI\%\-p\fP/=/foo.png \fI\%\-p\fP/doc=/bar.css
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-b, \-\-padding=<N>
+Add at most <N> bytes to a frame payload as padding.
+Specify 0 to disable padding.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-m, \-\-max\-concurrent\-streams=<N>
+Set the maximum number of the concurrent streams in one
+HTTP/2 session.
+.sp
+Default: \fB100\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-n, \-\-workers=<N>
+Set the number of worker threads.
+.sp
+Default: \fB1\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-e, \-\-error\-gzip
+Make error response gzipped.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-w, \-\-window\-bits=<N>
+Sets the stream level initial window size to 2**<N>\-1.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-W, \-\-connection\-window\-bits=<N>
+Sets the connection level initial window size to
+2**<N>\-1.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-dh\-param\-file=<PATH>
+Path to file that contains DH parameters in PEM format.
+Without this option, DHE cipher suites are not
+available.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-early\-response
+Start sending response when request HEADERS is received,
+rather than complete request is received.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-trailer=<HEADER>
+Add a trailer header to a response. <HEADER> must not
+include pseudo header field (header field name starting
+with \(aq:\(aq). The trailer is sent only if a response has
+body part. Example: \fI\%\-\-trailer\fP \(aqfoo: bar\(aq.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-hexdump
+Display the incoming traffic in hexadecimal (Canonical
+hex+ASCII display). If SSL/TLS is used, decrypted data
+are used.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-echo\-upload
+Send back uploaded content if method is POST or PUT.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-mime\-types\-file=<PATH>
+Path to file that contains MIME media types and the
+extensions that represent them.
+.sp
+Default: \fB/etc/mime.types\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-content\-length
+Don\(aqt send content\-length header field.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ktls
+Enable ktls.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-rfc7540\-pri
+Disable RFC7540 priorities.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-version
+Display version information and exit.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-h, \-\-help
+Display this help and exit.
+.UNINDENT
+.sp
+The <SIZE> argument is an integer and an optional unit (e.g., 10K is
+10 * 1024). Units are K, M and G (powers of 1024).
+.SH SEE ALSO
+.sp
+\fBnghttp(1)\fP, \fBnghttpx(1)\fP, \fBh2load(1)\fP
+.SH AUTHOR
+Tatsuhiro Tsujikawa
+.SH COPYRIGHT
+2012, 2015, 2016, Tatsuhiro Tsujikawa
+.\" Generated by docutils manpage writer.
+.
diff --git a/doc/nghttpd.1.rst b/doc/nghttpd.1.rst
new file mode 100644
index 0000000..654a025
--- /dev/null
+++ b/doc/nghttpd.1.rst
@@ -0,0 +1,186 @@
+
+.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
+
+.. program:: nghttpd
+
+nghttpd(1)
+==========
+
+SYNOPSIS
+--------
+
+**nghttpd** [OPTION]... <PORT> [<PRIVATE_KEY> <CERT>]
+
+DESCRIPTION
+-----------
+
+HTTP/2 server
+
+.. describe:: <PORT>
+
+ Specify listening port number.
+
+.. describe:: <PRIVATE_KEY>
+
+
+ Set path to server's private key. Required unless
+ :option:`--no-tls` is specified.
+
+.. describe:: <CERT>
+
+ Set path to server's certificate. Required unless
+ :option:`--no-tls` is specified.
+
+OPTIONS
+-------
+
+.. option:: -a, --address=<ADDR>
+
+ The address to bind to. If not specified the default IP
+ address determined by getaddrinfo is used.
+
+.. option:: -D, --daemon
+
+ Run in a background. If :option:`-D` is used, the current working
+ directory is changed to '*/*'. Therefore if this option
+ is used, :option:`-d` option must be specified.
+
+.. option:: -V, --verify-client
+
+ The server sends a client certificate request. If the
+ client did not return a certificate, the handshake is
+ terminated. Currently, this option just requests a
+ client certificate and does not verify it.
+
+.. option:: -d, --htdocs=<PATH>
+
+ Specify document root. If this option is not specified,
+ the document root is the current working directory.
+
+.. option:: -v, --verbose
+
+ Print debug information such as reception/ transmission
+ of frames and name/value pairs.
+
+.. option:: --no-tls
+
+ Disable SSL/TLS.
+
+.. option:: -c, --header-table-size=<SIZE>
+
+ Specify decoder header table size.
+
+.. option:: --encoder-header-table-size=<SIZE>
+
+ Specify encoder header table size. The decoder (client)
+ specifies the maximum dynamic table size it accepts.
+ Then the negotiated dynamic table size is the minimum of
+ this option value and the value which client specified.
+
+.. option:: --color
+
+ Force colored log output.
+
+.. option:: -p, --push=<PATH>=<PUSH_PATH,...>
+
+ Push resources <PUSH_PATH>s when <PATH> is requested.
+ This option can be used repeatedly to specify multiple
+ push configurations. <PATH> and <PUSH_PATH>s are
+ relative to document root. See :option:`--htdocs` option.
+ Example: :option:`-p`\/=/foo.png :option:`-p`\/doc=/bar.css
+
+.. option:: -b, --padding=<N>
+
+ Add at most <N> bytes to a frame payload as padding.
+ Specify 0 to disable padding.
+
+.. option:: -m, --max-concurrent-streams=<N>
+
+ Set the maximum number of the concurrent streams in one
+ HTTP/2 session.
+
+ Default: ``100``
+
+.. option:: -n, --workers=<N>
+
+ Set the number of worker threads.
+
+ Default: ``1``
+
+.. option:: -e, --error-gzip
+
+ Make error response gzipped.
+
+.. option:: -w, --window-bits=<N>
+
+ Sets the stream level initial window size to 2\*\*<N>-1.
+
+.. option:: -W, --connection-window-bits=<N>
+
+ Sets the connection level initial window size to
+ 2\*\*<N>-1.
+
+.. option:: --dh-param-file=<PATH>
+
+ Path to file that contains DH parameters in PEM format.
+ Without this option, DHE cipher suites are not
+ available.
+
+.. option:: --early-response
+
+ Start sending response when request HEADERS is received,
+ rather than complete request is received.
+
+.. option:: --trailer=<HEADER>
+
+ Add a trailer header to a response. <HEADER> must not
+ include pseudo header field (header field name starting
+ with ':'). The trailer is sent only if a response has
+ body part. Example: :option:`--trailer` 'foo: bar'.
+
+.. option:: --hexdump
+
+ Display the incoming traffic in hexadecimal (Canonical
+ hex+ASCII display). If SSL/TLS is used, decrypted data
+ are used.
+
+.. option:: --echo-upload
+
+ Send back uploaded content if method is POST or PUT.
+
+.. option:: --mime-types-file=<PATH>
+
+ Path to file that contains MIME media types and the
+ extensions that represent them.
+
+ Default: ``/etc/mime.types``
+
+.. option:: --no-content-length
+
+ Don't send content-length header field.
+
+.. option:: --ktls
+
+ Enable ktls.
+
+.. option:: --no-rfc7540-pri
+
+ Disable RFC7540 priorities.
+
+.. option:: --version
+
+ Display version information and exit.
+
+.. option:: -h, --help
+
+ Display this help and exit.
+
+
+
+The <SIZE> argument is an integer and an optional unit (e.g., 10K is
+10 * 1024). Units are K, M and G (powers of 1024).
+
+SEE ALSO
+--------
+
+:manpage:`nghttp(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`
diff --git a/doc/nghttpd.h2r b/doc/nghttpd.h2r
new file mode 100644
index 0000000..e346cd1
--- /dev/null
+++ b/doc/nghttpd.h2r
@@ -0,0 +1,4 @@
+SEE ALSO
+--------
+
+:manpage:`nghttp(1)`, :manpage:`nghttpx(1)`, :manpage:`h2load(1)`
diff --git a/doc/nghttpx-howto.rst.in b/doc/nghttpx-howto.rst.in
new file mode 100644
index 0000000..082ce51
--- /dev/null
+++ b/doc/nghttpx-howto.rst.in
@@ -0,0 +1 @@
+.. include:: @top_srcdir@/doc/sources/nghttpx-howto.rst
diff --git a/doc/nghttpx.1 b/doc/nghttpx.1
new file mode 100644
index 0000000..e9742a5
--- /dev/null
+++ b/doc/nghttpx.1
@@ -0,0 +1,2770 @@
+.\" Man page generated from reStructuredText.
+.
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.TH "NGHTTPX" "1" "Jan 21, 2024" "1.59.0" "nghttp2"
+.SH NAME
+nghttpx \- HTTP/2 proxy
+.SH SYNOPSIS
+.sp
+\fBnghttpx\fP [OPTIONS]... [<PRIVATE_KEY> <CERT>]
+.SH DESCRIPTION
+.sp
+A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.
+.INDENT 0.0
+.TP
+.B <PRIVATE_KEY>
+Set path to server\(aqs private key. Required unless
+\(dqno\-tls\(dq parameter is used in \fI\%\-\-frontend\fP option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B <CERT>
+Set path to server\(aqs certificate. Required unless
+\(dqno\-tls\(dq parameter is used in \fI\%\-\-frontend\fP option. To
+make OCSP stapling work, this must be an absolute path.
+.UNINDENT
+.SH OPTIONS
+.sp
+The options are categorized into several groups.
+.SS Connections
+.INDENT 0.0
+.TP
+.B \-b, \-\-backend=(<HOST>,<PORT>|unix:<PATH>)[;[<PATTERN>[:...]][[;<PARAM>]...]
+Set backend host and port. The multiple backend
+addresses are accepted by repeating this option. UNIX
+domain socket can be specified by prefixing path name
+with \(dqunix:\(dq (e.g., unix:/var/run/backend.sock).
+.sp
+Optionally, if <PATTERN>s are given, the backend address
+is only used if request matches the pattern. The
+pattern matching is closely designed to ServeMux in
+net/http package of Go programming language. <PATTERN>
+consists of path, host + path or just host. The path
+must start with \(dq\fI/\fP\(dq. If it ends with \(dq\fI/\fP\(dq, it matches
+all request path in its subtree. To deal with the
+request to the directory without trailing slash, the
+path which ends with \(dq\fI/\fP\(dq also matches the request path
+which only lacks trailing \(aq\fI/\fP\(aq (e.g., path \(dq\fI/foo/\fP\(dq
+matches request path \(dq\fI/foo\fP\(dq). If it does not end with
+\(dq\fI/\fP\(dq, it performs exact match against the request path.
+If host is given, it performs a match against the
+request host. For a request received on the frontend
+listener with \(dqsni\-fwd\(dq parameter enabled, SNI host is
+used instead of a request host. If host alone is given,
+\(dq\fI/\fP\(dq is appended to it, so that it matches all request
+paths under the host (e.g., specifying \(dqnghttp2.org\(dq
+equals to \(dqnghttp2.org/\(dq). CONNECT method is treated
+specially. It does not have path, and we don\(aqt allow
+empty path. To workaround this, we assume that CONNECT
+method has \(dq\fI/\fP\(dq as path.
+.sp
+Patterns with host take precedence over patterns with
+just path. Then, longer patterns take precedence over
+shorter ones.
+.sp
+Host can include \(dq*\(dq in the left most position to
+indicate wildcard match (only suffix match is done).
+The \(dq*\(dq must match at least one character. For example,
+host pattern \(dq*.nghttp2.org\(dq matches against
+\(dqwww.nghttp2.org\(dq and \(dqgit.ngttp2.org\(dq, but does not
+match against \(dqnghttp2.org\(dq. The exact hosts match
+takes precedence over the wildcard hosts match.
+.sp
+If path part ends with \(dq*\(dq, it is treated as wildcard
+path. The wildcard path behaves differently from the
+normal path. For normal path, match is made around the
+boundary of path component separator,\(dq\fI/\fP\(dq. On the other
+hand, the wildcard path does not take into account the
+path component separator. All paths which include the
+wildcard path without last \(dq*\(dq as prefix, and are
+strictly longer than wildcard path without last \(dq*\(dq are
+matched. \(dq*\(dq must match at least one character. For
+example, the pattern \(dq\fI/foo*\fP\(dq matches \(dq\fI/foo/\fP\(dq and
+\(dq\fI/foobar\fP\(dq. But it does not match \(dq\fI/foo\fP\(dq, or \(dq\fI/fo\fP\(dq.
+.sp
+If <PATTERN> is omitted or empty string, \(dq\fI/\fP\(dq is used as
+pattern, which matches all request paths (catch\-all
+pattern). The catch\-all backend must be given.
+.sp
+When doing a match, nghttpx made some normalization to
+pattern, request host and path. For host part, they are
+converted to lower case. For path part, percent\-encoded
+unreserved characters defined in RFC 3986 are decoded,
+and any dot\-segments (\(dq..\(dq and \(dq.\(dq) are resolved and
+removed.
+.sp
+For example, \fI\%\-b\fP\(aq127.0.0.1,8080;nghttp2.org/httpbin/\(aq
+matches the request host \(dqnghttp2.org\(dq and the request
+path \(dq\fI/httpbin/get\fP\(dq, but does not match the request host
+\(dqnghttp2.org\(dq and the request path \(dq\fI/index.html\fP\(dq.
+.sp
+The multiple <PATTERN>s can be specified, delimiting
+them by \(dq:\(dq. Specifying
+\fI\%\-b\fP\(aq127.0.0.1,8080;nghttp2.org:www.nghttp2.org\(aq has the
+same effect to specify \fI\%\-b\fP\(aq127.0.0.1,8080;nghttp2.org\(aq
+and \fI\%\-b\fP\(aq127.0.0.1,8080;www.nghttp2.org\(aq.
+.sp
+The backend addresses sharing same <PATTERN> are grouped
+together forming load balancing group.
+.sp
+Several parameters <PARAM> are accepted after <PATTERN>.
+The parameters are delimited by \(dq;\(dq. The available
+parameters are: \(dqproto=<PROTO>\(dq, \(dqtls\(dq,
+\(dqsni=<SNI_HOST>\(dq, \(dqfall=<N>\(dq, \(dqrise=<N>\(dq,
+\(dqaffinity=<METHOD>\(dq, \(dqdns\(dq, \(dqredirect\-if\-not\-tls\(dq,
+\(dqupgrade\-scheme\(dq, \(dqmruby=<PATH>\(dq,
+\(dqread\-timeout=<DURATION>\(dq, \(dqwrite\-timeout=<DURATION>\(dq,
+\(dqgroup=<GROUP>\(dq, \(dqgroup\-weight=<N>\(dq, \(dqweight=<N>\(dq, and
+\(dqdnf\(dq. The parameter consists of keyword, and
+optionally followed by \(dq=\(dq and value. For example, the
+parameter \(dqproto=h2\(dq consists of the keyword \(dqproto\(dq and
+value \(dqh2\(dq. The parameter \(dqtls\(dq consists of the keyword
+\(dqtls\(dq without value. Each parameter is described as
+follows.
+.sp
+The backend application protocol can be specified using
+optional \(dqproto\(dq parameter, and in the form of
+\(dqproto=<PROTO>\(dq. <PROTO> should be one of the following
+list without quotes: \(dqh2\(dq, \(dqhttp/1.1\(dq. The default
+value of <PROTO> is \(dqhttp/1.1\(dq. Note that usually \(dqh2\(dq
+refers to HTTP/2 over TLS. But in this option, it may
+mean HTTP/2 over cleartext TCP unless \(dqtls\(dq keyword is
+used (see below).
+.sp
+TLS can be enabled by specifying optional \(dqtls\(dq
+parameter. TLS is not enabled by default.
+.sp
+With \(dqsni=<SNI_HOST>\(dq parameter, it can override the TLS
+SNI field value with given <SNI_HOST>. This will
+default to the backend <HOST> name
+.sp
+The feature to detect whether backend is online or
+offline can be enabled using optional \(dqfall\(dq and \(dqrise\(dq
+parameters. Using \(dqfall=<N>\(dq parameter, if nghttpx
+cannot connect to a this backend <N> times in a row,
+this backend is assumed to be offline, and it is
+excluded from load balancing. If <N> is 0, this backend
+never be excluded from load balancing whatever times
+nghttpx cannot connect to it, and this is the default.
+There is also \(dqrise=<N>\(dq parameter. After backend was
+excluded from load balancing group, nghttpx periodically
+attempts to make a connection to the failed backend, and
+if the connection is made successfully <N> times in a
+row, the backend is assumed to be online, and it is now
+eligible for load balancing target. If <N> is 0, a
+backend is permanently offline, once it goes in that
+state, and this is the default behaviour.
+.sp
+The session affinity is enabled using
+\(dqaffinity=<METHOD>\(dq parameter. If \(dqip\(dq is given in
+<METHOD>, client IP based session affinity is enabled.
+If \(dqcookie\(dq is given in <METHOD>, cookie based session
+affinity is enabled. If \(dqnone\(dq is given in <METHOD>,
+session affinity is disabled, and this is the default.
+The session affinity is enabled per <PATTERN>. If at
+least one backend has \(dqaffinity\(dq parameter, and its
+<METHOD> is not \(dqnone\(dq, session affinity is enabled for
+all backend servers sharing the same <PATTERN>. It is
+advised to set \(dqaffinity\(dq parameter to all backend
+explicitly if session affinity is desired. The session
+affinity may break if one of the backend gets
+unreachable, or backend settings are reloaded or
+replaced by API.
+.sp
+If \(dqaffinity=cookie\(dq is used, the additional
+configuration is required.
+\(dqaffinity\-cookie\-name=<NAME>\(dq must be used to specify a
+name of cookie to use. Optionally,
+\(dqaffinity\-cookie\-path=<PATH>\(dq can be used to specify a
+path which cookie is applied. The optional
+\(dqaffinity\-cookie\-secure=<SECURE>\(dq controls the Secure
+attribute of a cookie. The default value is \(dqauto\(dq, and
+the Secure attribute is determined by a request scheme.
+If a request scheme is \(dqhttps\(dq, then Secure attribute is
+set. Otherwise, it is not set. If <SECURE> is \(dqyes\(dq,
+the Secure attribute is always set. If <SECURE> is
+\(dqno\(dq, the Secure attribute is always omitted.
+\(dqaffinity\-cookie\-stickiness=<STICKINESS>\(dq controls
+stickiness of this affinity. If <STICKINESS> is
+\(dqloose\(dq, removing or adding a backend server might break
+the affinity and the request might be forwarded to a
+different backend server. If <STICKINESS> is \(dqstrict\(dq,
+removing the designated backend server breaks affinity,
+but adding new backend server does not cause breakage.
+If the designated backend server becomes unavailable,
+new backend server is chosen as if the request does not
+have an affinity cookie. <STICKINESS> defaults to
+\(dqloose\(dq.
+.sp
+By default, name resolution of backend host name is done
+at start up, or reloading configuration. If \(dqdns\(dq
+parameter is given, name resolution takes place
+dynamically. This is useful if backend address changes
+frequently. If \(dqdns\(dq is given, name resolution of
+backend host name at start up, or reloading
+configuration is skipped.
+.sp
+If \(dqredirect\-if\-not\-tls\(dq parameter is used, the matched
+backend requires that frontend connection is TLS
+encrypted. If it isn\(aqt, nghttpx responds to the request
+with 308 status code, and https URI the client should
+use instead is included in Location header field. The
+port number in redirect URI is 443 by default, and can
+be changed using \fI\%\-\-redirect\-https\-port\fP option. If at
+least one backend has \(dqredirect\-if\-not\-tls\(dq parameter,
+this feature is enabled for all backend servers sharing
+the same <PATTERN>. It is advised to set
+\(dqredirect\-if\-no\-tls\(dq parameter to all backends
+explicitly if this feature is desired.
+.sp
+If \(dqupgrade\-scheme\(dq parameter is used along with \(dqtls\(dq
+parameter, HTTP/2 :scheme pseudo header field is changed
+to \(dqhttps\(dq from \(dqhttp\(dq when forwarding a request to this
+particular backend. This is a workaround for a backend
+server which requires \(dqhttps\(dq :scheme pseudo header
+field on TLS encrypted connection.
+.sp
+\(dqmruby=<PATH>\(dq parameter specifies a path to mruby
+script file which is invoked when this pattern is
+matched. All backends which share the same pattern must
+have the same mruby path.
+.sp
+\(dqread\-timeout=<DURATION>\(dq and \(dqwrite\-timeout=<DURATION>\(dq
+parameters specify the read and write timeout of the
+backend connection when this pattern is matched. All
+backends which share the same pattern must have the same
+timeouts. If these timeouts are entirely omitted for a
+pattern, \fI\%\-\-backend\-read\-timeout\fP and
+\fI\%\-\-backend\-write\-timeout\fP are used.
+.sp
+\(dqgroup=<GROUP>\(dq parameter specifies the name of group
+this backend address belongs to. By default, it belongs
+to the unnamed default group. The name of group is
+unique per pattern. \(dqgroup\-weight=<N>\(dq parameter
+specifies the weight of the group. The higher weight
+gets more frequently selected by the load balancing
+algorithm. <N> must be [1, 256] inclusive. The weight
+8 has 4 times more weight than 2. <N> must be the same
+for all addresses which share the same <GROUP>. If
+\(dqgroup\-weight\(dq is omitted in an address, but the other
+address which belongs to the same group specifies
+\(dqgroup\-weight\(dq, its weight is used. If no
+\(dqgroup\-weight\(dq is specified for all addresses, the
+weight of a group becomes 1. \(dqgroup\(dq and \(dqgroup\-weight\(dq
+are ignored if session affinity is enabled.
+.sp
+\(dqweight=<N>\(dq parameter specifies the weight of the
+backend address inside a group which this address
+belongs to. The higher weight gets more frequently
+selected by the load balancing algorithm. <N> must be
+[1, 256] inclusive. The weight 8 has 4 times more
+weight than weight 2. If this parameter is omitted,
+weight becomes 1. \(dqweight\(dq is ignored if session
+affinity is enabled.
+.sp
+If \(dqdnf\(dq parameter is specified, an incoming request is
+not forwarded to a backend and just consumed along with
+the request body (actually a backend server never be
+contacted). It is expected that the HTTP response is
+generated by mruby script (see \(dqmruby=<PATH>\(dq parameter
+above). \(dqdnf\(dq is an abbreviation of \(dqdo not forward\(dq.
+.sp
+Since \(dq;\(dq and \(dq:\(dq are used as delimiter, <PATTERN> must
+not contain these characters. In order to include \(dq:\(dq
+in <PATTERN>, one has to specify \(dq%3A\(dq (which is
+percent\-encoded from of \(dq:\(dq) instead. Since \(dq;\(dq has
+special meaning in shell, the option value must be
+quoted.
+.sp
+Default: \fB127.0.0.1,80\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-f, \-\-frontend=(<HOST>,<PORT>|unix:<PATH>)[[;<PARAM>]...]
+Set frontend host and port. If <HOST> is \(aq*\(aq, it
+assumes all addresses including both IPv4 and IPv6.
+UNIX domain socket can be specified by prefixing path
+name with \(dqunix:\(dq (e.g., unix:/var/run/nghttpx.sock).
+This option can be used multiple times to listen to
+multiple addresses.
+.sp
+This option can take 0 or more parameters, which are
+described below. Note that \(dqapi\(dq and \(dqhealthmon\(dq
+parameters are mutually exclusive.
+.sp
+Optionally, TLS can be disabled by specifying \(dqno\-tls\(dq
+parameter. TLS is enabled by default.
+.sp
+If \(dqsni\-fwd\(dq parameter is used, when performing a match
+to select a backend server, SNI host name received from
+the client is used instead of the request host. See
+\fI\%\-\-backend\fP option about the pattern match.
+.sp
+To make this frontend as API endpoint, specify \(dqapi\(dq
+parameter. This is disabled by default. It is
+important to limit the access to the API frontend.
+Otherwise, someone may change the backend server, and
+break your services, or expose confidential information
+to the outside the world.
+.sp
+To make this frontend as health monitor endpoint,
+specify \(dqhealthmon\(dq parameter. This is disabled by
+default. Any requests which come through this address
+are replied with 200 HTTP status, without no body.
+.sp
+To accept PROXY protocol version 1 and 2 on frontend
+connection, specify \(dqproxyproto\(dq parameter. This is
+disabled by default.
+.sp
+To receive HTTP/3 (QUIC) traffic, specify \(dqquic\(dq
+parameter. It makes nghttpx listen on UDP port rather
+than TCP port. UNIX domain socket, \(dqapi\(dq, and
+\(dqhealthmon\(dq parameters cannot be used with \(dqquic\(dq
+parameter.
+.sp
+Default: \fB*,3000\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backlog=<N>
+Set listen backlog size.
+.sp
+Default: \fB65536\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-address\-family=(auto|IPv4|IPv6)
+Specify address family of backend connections. If
+\(dqauto\(dq is given, both IPv4 and IPv6 are considered. If
+\(dqIPv4\(dq is given, only IPv4 address is considered. If
+\(dqIPv6\(dq is given, only IPv6 address is considered.
+.sp
+Default: \fBauto\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-http\-proxy\-uri=<URI>
+Specify proxy URI in the form
+\fI\%http:/\fP/[<USER>:<PASS>@]<PROXY>:<PORT>. If a proxy
+requires authentication, specify <USER> and <PASS>.
+Note that they must be properly percent\-encoded. This
+proxy is used when the backend connection is HTTP/2.
+First, make a CONNECT request to the proxy and it
+connects to the backend on behalf of nghttpx. This
+forms tunnel. After that, nghttpx performs SSL/TLS
+handshake with the downstream through the tunnel. The
+timeouts when connecting and making CONNECT request can
+be specified by \fI\%\-\-backend\-read\-timeout\fP and
+\fI\%\-\-backend\-write\-timeout\fP options.
+.UNINDENT
+.SS Performance
+.INDENT 0.0
+.TP
+.B \-n, \-\-workers=<N>
+Set the number of worker threads.
+.sp
+Default: \fB1\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-single\-thread
+Run everything in one thread inside the worker process.
+This feature is provided for better debugging
+experience, or for the platforms which lack thread
+support. If threading is disabled, this option is
+always enabled.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-read\-rate=<SIZE>
+Set maximum average read rate on frontend connection.
+Setting 0 to this option means read rate is unlimited.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-read\-burst=<SIZE>
+Set maximum read burst size on frontend connection.
+Setting 0 to this option means read burst size is
+unlimited.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-write\-rate=<SIZE>
+Set maximum average write rate on frontend connection.
+Setting 0 to this option means write rate is unlimited.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-write\-burst=<SIZE>
+Set maximum write burst size on frontend connection.
+Setting 0 to this option means write burst size is
+unlimited.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-worker\-read\-rate=<SIZE>
+Set maximum average read rate on frontend connection per
+worker. Setting 0 to this option means read rate is
+unlimited. Not implemented yet.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-worker\-read\-burst=<SIZE>
+Set maximum read burst size on frontend connection per
+worker. Setting 0 to this option means read burst size
+is unlimited. Not implemented yet.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-worker\-write\-rate=<SIZE>
+Set maximum average write rate on frontend connection
+per worker. Setting 0 to this option means write rate
+is unlimited. Not implemented yet.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-worker\-write\-burst=<SIZE>
+Set maximum write burst size on frontend connection per
+worker. Setting 0 to this option means write burst size
+is unlimited. Not implemented yet.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-worker\-frontend\-connections=<N>
+Set maximum number of simultaneous connections frontend
+accepts. Setting 0 means unlimited.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-connections\-per\-host=<N>
+Set maximum number of backend concurrent connections
+(and/or streams in case of HTTP/2) per origin host.
+This option is meaningful when \fI\%\-\-http2\-proxy\fP option is
+used. The origin host is determined by authority
+portion of request URI (or :authority header field for
+HTTP/2). To limit the number of connections per
+frontend for default mode, use
+\fI\%\-\-backend\-connections\-per\-frontend\fP\&.
+.sp
+Default: \fB8\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-connections\-per\-frontend=<N>
+Set maximum number of backend concurrent connections
+(and/or streams in case of HTTP/2) per frontend. This
+option is only used for default mode. 0 means
+unlimited. To limit the number of connections per host
+with \fI\%\-\-http2\-proxy\fP option, use
+\fI\%\-\-backend\-connections\-per\-host\fP\&.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-rlimit\-nofile=<N>
+Set maximum number of open files (RLIMIT_NOFILE) to <N>.
+If 0 is given, nghttpx does not set the limit.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-rlimit\-memlock=<N>
+Set maximum number of bytes of memory that may be locked
+into RAM. If 0 is given, nghttpx does not set the
+limit.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-request\-buffer=<SIZE>
+Set buffer size used to store backend request.
+.sp
+Default: \fB16K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-response\-buffer=<SIZE>
+Set buffer size used to store backend response.
+.sp
+Default: \fB128K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-fastopen=<N>
+Enables \(dqTCP Fast Open\(dq for the listening socket and
+limits the maximum length for the queue of connections
+that have not yet completed the three\-way handshake. If
+value is 0 then fast open is disabled.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-kqueue
+Don\(aqt use kqueue. This option is only applicable for
+the platforms which have kqueue. For other platforms,
+this option will be simply ignored.
+.UNINDENT
+.SS Timeout
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-read\-timeout=<DURATION>
+Specify read timeout for HTTP/2 frontend connection.
+.sp
+Default: \fB3m\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http3\-read\-timeout=<DURATION>
+Specify read timeout for HTTP/3 frontend connection.
+.sp
+Default: \fB3m\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-read\-timeout=<DURATION>
+Specify read timeout for HTTP/1.1 frontend connection.
+.sp
+Default: \fB1m\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-write\-timeout=<DURATION>
+Specify write timeout for all frontend connections.
+.sp
+Default: \fB30s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-keep\-alive\-timeout=<DURATION>
+Specify keep\-alive timeout for frontend HTTP/1
+connection.
+.sp
+Default: \fB1m\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-stream\-read\-timeout=<DURATION>
+Specify read timeout for HTTP/2 streams. 0 means no
+timeout.
+.sp
+Default: \fB0\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-stream\-write\-timeout=<DURATION>
+Specify write timeout for HTTP/2 streams. 0 means no
+timeout.
+.sp
+Default: \fB1m\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-read\-timeout=<DURATION>
+Specify read timeout for backend connection.
+.sp
+Default: \fB1m\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-write\-timeout=<DURATION>
+Specify write timeout for backend connection.
+.sp
+Default: \fB30s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-connect\-timeout=<DURATION>
+Specify timeout before establishing TCP connection to
+backend.
+.sp
+Default: \fB30s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-keep\-alive\-timeout=<DURATION>
+Specify keep\-alive timeout for backend HTTP/1
+connection.
+.sp
+Default: \fB2s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-listener\-disable\-timeout=<DURATION>
+After accepting connection failed, connection listener
+is disabled for a given amount of time. Specifying 0
+disables this feature.
+.sp
+Default: \fB30s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-setting\-timeout=<DURATION>
+Specify timeout before SETTINGS ACK is received from
+client.
+.sp
+Default: \fB10s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-http2\-settings\-timeout=<DURATION>
+Specify timeout before SETTINGS ACK is received from
+backend server.
+.sp
+Default: \fB10s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-max\-backoff=<DURATION>
+Specify maximum backoff interval. This is used when
+doing health check against offline backend (see \(dqfail\(dq
+parameter in \fI\%\-\-backend\fP option). It is also used to
+limit the maximum interval to temporarily disable
+backend when nghttpx failed to connect to it. These
+intervals are calculated using exponential backoff, and
+consecutive failed attempts increase the interval. This
+option caps its maximum value.
+.sp
+Default: \fB2m\fP
+.UNINDENT
+.SS SSL/TLS
+.INDENT 0.0
+.TP
+.B \-\-ciphers=<SUITE>
+Set allowed cipher list for frontend connection. The
+format of the string is described in OpenSSL ciphers(1).
+This option sets cipher suites for TLSv1.2 or earlier.
+Use \fI\%\-\-tls13\-ciphers\fP for TLSv1.3.
+.sp
+Default: \fBECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:DHE\-RSA\-AES128\-GCM\-SHA256:DHE\-RSA\-AES256\-GCM\-SHA384\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls13\-ciphers=<SUITE>
+Set allowed cipher list for frontend connection. The
+format of the string is described in OpenSSL ciphers(1).
+This option sets cipher suites for TLSv1.3. Use
+\fI\%\-\-ciphers\fP for TLSv1.2 or earlier.
+.sp
+Default: \fBTLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-client\-ciphers=<SUITE>
+Set allowed cipher list for backend connection. The
+format of the string is described in OpenSSL ciphers(1).
+This option sets cipher suites for TLSv1.2 or earlier.
+Use \fI\%\-\-tls13\-client\-ciphers\fP for TLSv1.3.
+.sp
+Default: \fBECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:DHE\-RSA\-AES128\-GCM\-SHA256:DHE\-RSA\-AES256\-GCM\-SHA384\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls13\-client\-ciphers=<SUITE>
+Set allowed cipher list for backend connection. The
+format of the string is described in OpenSSL ciphers(1).
+This option sets cipher suites for TLSv1.3. Use
+\fI\%\-\-tls13\-client\-ciphers\fP for TLSv1.2 or earlier.
+.sp
+Default: \fBTLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ecdh\-curves=<LIST>
+Set supported curve list for frontend connections.
+<LIST> is a colon separated list of curve NID or names
+in the preference order. The supported curves depend on
+the linked OpenSSL library. This function requires
+OpenSSL >= 1.0.2.
+.sp
+Default: \fBX25519:P\-256:P\-384:P\-521\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-k, \-\-insecure
+Don\(aqt verify backend server\(aqs certificate if TLS is
+enabled for backend connections.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-cacert=<PATH>
+Set path to trusted CA certificate file. It is used in
+backend TLS connections to verify peer\(aqs certificate.
+It is also used to verify OCSP response from the script
+set by \fI\%\-\-fetch\-ocsp\-response\-file\fP\&. The file must be in
+PEM format. It can contain multiple certificates. If
+the linked OpenSSL is configured to load system wide
+certificates, they are loaded at startup regardless of
+this option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-private\-key\-passwd\-file=<PATH>
+Path to file that contains password for the server\(aqs
+private key. If none is given and the private key is
+password protected it\(aqll be requested interactively.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-subcert=<KEYPATH>:<CERTPATH>[[;<PARAM>]...]
+Specify additional certificate and private key file.
+nghttpx will choose certificates based on the hostname
+indicated by client using TLS SNI extension. If nghttpx
+is built with OpenSSL >= 1.0.2, the shared elliptic
+curves (e.g., P\-256) between client and server are also
+taken into consideration. This allows nghttpx to send
+ECDSA certificate to modern clients, while sending RSA
+based certificate to older clients. This option can be
+used multiple times. To make OCSP stapling work,
+<CERTPATH> must be absolute path.
+.sp
+Additional parameter can be specified in <PARAM>. The
+available <PARAM> is \(dqsct\-dir=<DIR>\(dq.
+.sp
+\(dqsct\-dir=<DIR>\(dq specifies the path to directory which
+contains *.sct files for TLS
+signed_certificate_timestamp extension (RFC 6962). This
+feature requires OpenSSL >= 1.0.2. See also
+\fI\%\-\-tls\-sct\-dir\fP option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-dh\-param\-file=<PATH>
+Path to file that contains DH parameters in PEM format.
+Without this option, DHE cipher suites are not
+available.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-alpn\-list=<LIST>
+Comma delimited list of ALPN protocol identifier sorted
+in the order of preference. That means most desirable
+protocol comes first. The parameter must be delimited
+by a single comma only and any white spaces are treated
+as a part of protocol string.
+.sp
+Default: \fBh2,h2\-16,h2\-14,http/1.1\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-verify\-client
+Require and verify client certificate.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-verify\-client\-cacert=<PATH>
+Path to file that contains CA certificates to verify
+client certificate. The file must be in PEM format. It
+can contain multiple certificates.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-verify\-client\-tolerate\-expired
+Accept expired client certificate. Operator should
+handle the expired client certificate by some means
+(e.g., mruby script). Otherwise, this option might
+cause a security risk.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-client\-private\-key\-file=<PATH>
+Path to file that contains client private key used in
+backend client authentication.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-client\-cert\-file=<PATH>
+Path to file that contains client certificate used in
+backend client authentication.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-min\-proto\-version=<VER>
+Specify minimum SSL/TLS protocol. The name matching is
+done in case\-insensitive manner. The versions between
+\fI\%\-\-tls\-min\-proto\-version\fP and \fI\%\-\-tls\-max\-proto\-version\fP are
+enabled. If the protocol list advertised by client does
+not overlap this range, you will receive the error
+message \(dqunknown protocol\(dq. If a protocol version lower
+than TLSv1.2 is specified, make sure that the compatible
+ciphers are included in \fI\%\-\-ciphers\fP option. The default
+cipher list only includes ciphers compatible with
+TLSv1.2 or above. The available versions are:
+TLSv1.3, TLSv1.2, TLSv1.1, and TLSv1.0
+.sp
+Default: \fBTLSv1.2\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-max\-proto\-version=<VER>
+Specify maximum SSL/TLS protocol. The name matching is
+done in case\-insensitive manner. The versions between
+\fI\%\-\-tls\-min\-proto\-version\fP and \fI\%\-\-tls\-max\-proto\-version\fP are
+enabled. If the protocol list advertised by client does
+not overlap this range, you will receive the error
+message \(dqunknown protocol\(dq. The available versions are:
+TLSv1.3, TLSv1.2, TLSv1.1, and TLSv1.0
+.sp
+Default: \fBTLSv1.3\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-file=<PATH>
+Path to file that contains random data to construct TLS
+session ticket parameters. If aes\-128\-cbc is given in
+\fI\%\-\-tls\-ticket\-key\-cipher\fP, the file must contain exactly
+48 bytes. If aes\-256\-cbc is given in
+\fI\%\-\-tls\-ticket\-key\-cipher\fP, the file must contain exactly
+80 bytes. This options can be used repeatedly to
+specify multiple ticket parameters. If several files
+are given, only the first key is used to encrypt TLS
+session tickets. Other keys are accepted but server
+will issue new session ticket with first key. This
+allows session key rotation. Please note that key
+rotation does not occur automatically. User should
+rearrange files or change options values and restart
+nghttpx gracefully. If opening or reading given file
+fails, all loaded keys are discarded and it is treated
+as if none of this option is given. If this option is
+not given or an error occurred while opening or reading
+a file, key is generated every 1 hour internally and
+they are valid for 12 hours. This is recommended if
+ticket key sharing between nghttpx instances is not
+required.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-memcached=<HOST>,<PORT>[;tls]
+Specify address of memcached server to get TLS ticket
+keys for session resumption. This enables shared TLS
+ticket key between multiple nghttpx instances. nghttpx
+does not set TLS ticket key to memcached. The external
+ticket key generator is required. nghttpx just gets TLS
+ticket keys from memcached, and use them, possibly
+replacing current set of keys. It is up to extern TLS
+ticket key generator to rotate keys frequently. See
+\(dqTLS SESSION TICKET RESUMPTION\(dq section in manual page
+to know the data format in memcached entry. Optionally,
+memcached connection can be encrypted with TLS by
+specifying \(dqtls\(dq parameter.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-memcached\-address\-family=(auto|IPv4|IPv6)
+Specify address family of memcached connections to get
+TLS ticket keys. If \(dqauto\(dq is given, both IPv4 and IPv6
+are considered. If \(dqIPv4\(dq is given, only IPv4 address
+is considered. If \(dqIPv6\(dq is given, only IPv6 address is
+considered.
+.sp
+Default: \fBauto\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-memcached\-interval=<DURATION>
+Set interval to get TLS ticket keys from memcached.
+.sp
+Default: \fB10m\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-memcached\-max\-retry=<N>
+Set maximum number of consecutive retries before
+abandoning TLS ticket key retrieval. If this number is
+reached, the attempt is considered as failure, and
+\(dqfailure\(dq count is incremented by 1, which contributed
+to the value controlled
+\fI\%\-\-tls\-ticket\-key\-memcached\-max\-fail\fP option.
+.sp
+Default: \fB3\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-memcached\-max\-fail=<N>
+Set maximum number of consecutive failure before
+disabling TLS ticket until next scheduled key retrieval.
+.sp
+Default: \fB2\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-cipher=<CIPHER>
+Specify cipher to encrypt TLS session ticket. Specify
+either aes\-128\-cbc or aes\-256\-cbc. By default,
+aes\-128\-cbc is used.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-memcached\-cert\-file=<PATH>
+Path to client certificate for memcached connections to
+get TLS ticket keys.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ticket\-key\-memcached\-private\-key\-file=<PATH>
+Path to client private key for memcached connections to
+get TLS ticket keys.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-fetch\-ocsp\-response\-file=<PATH>
+Path to fetch\-ocsp\-response script file. It should be
+absolute path.
+.sp
+Default: \fB/usr/local/share/nghttp2/fetch\-ocsp\-response\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ocsp\-update\-interval=<DURATION>
+Set interval to update OCSP response cache.
+.sp
+Default: \fB4h\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ocsp\-startup
+Start accepting connections after initial attempts to
+get OCSP responses finish. It does not matter some of
+the attempts fail. This feature is useful if OCSP
+responses must be available before accepting
+connections.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-verify\-ocsp
+nghttpx does not verify OCSP response.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-ocsp
+Disable OCSP stapling.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-session\-cache\-memcached=<HOST>,<PORT>[;tls]
+Specify address of memcached server to store session
+cache. This enables shared session cache between
+multiple nghttpx instances. Optionally, memcached
+connection can be encrypted with TLS by specifying \(dqtls\(dq
+parameter.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-session\-cache\-memcached\-address\-family=(auto|IPv4|IPv6)
+Specify address family of memcached connections to store
+session cache. If \(dqauto\(dq is given, both IPv4 and IPv6
+are considered. If \(dqIPv4\(dq is given, only IPv4 address
+is considered. If \(dqIPv6\(dq is given, only IPv6 address is
+considered.
+.sp
+Default: \fBauto\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-session\-cache\-memcached\-cert\-file=<PATH>
+Path to client certificate for memcached connections to
+store session cache.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-session\-cache\-memcached\-private\-key\-file=<PATH>
+Path to client private key for memcached connections to
+store session cache.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-dyn\-rec\-warmup\-threshold=<SIZE>
+Specify the threshold size for TLS dynamic record size
+behaviour. During a TLS session, after the threshold
+number of bytes have been written, the TLS record size
+will be increased to the maximum allowed (16K). The max
+record size will continue to be used on the active TLS
+session. After \fI\%\-\-tls\-dyn\-rec\-idle\-timeout\fP has elapsed,
+the record size is reduced to 1300 bytes. Specify 0 to
+always use the maximum record size, regardless of idle
+period. This behaviour applies to all TLS based
+frontends, and TLS HTTP/2 backends.
+.sp
+Default: \fB1M\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-dyn\-rec\-idle\-timeout=<DURATION>
+Specify TLS dynamic record size behaviour timeout. See
+\fI\%\-\-tls\-dyn\-rec\-warmup\-threshold\fP for more information.
+This behaviour applies to all TLS based frontends, and
+TLS HTTP/2 backends.
+.sp
+Default: \fB1s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-http2\-cipher\-block\-list
+Allow block listed cipher suite on frontend HTTP/2
+connection. See
+\fI\%https://tools.ietf.org/html/rfc7540#appendix\-A\fP for the
+complete HTTP/2 cipher suites block list.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-client\-no\-http2\-cipher\-block\-list
+Allow block listed cipher suite on backend HTTP/2
+connection. See
+\fI\%https://tools.ietf.org/html/rfc7540#appendix\-A\fP for the
+complete HTTP/2 cipher suites block list.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-sct\-dir=<DIR>
+Specifies the directory where *.sct files exist. All
+*.sct files in <DIR> are read, and sent as
+extension_data of TLS signed_certificate_timestamp (RFC
+6962) to client. These *.sct files are for the
+certificate specified in positional command\-line
+argument <CERT>, or certificate option in configuration
+file. For additional certificates, use \fI\%\-\-subcert\fP
+option. This option requires OpenSSL >= 1.0.2.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-psk\-secrets=<PATH>
+Read list of PSK identity and secrets from <PATH>. This
+is used for frontend connection. The each line of input
+file is formatted as <identity>:<hex\-secret>, where
+<identity> is PSK identity, and <hex\-secret> is secret
+in hex. An empty line, and line which starts with \(aq#\(aq
+are skipped. The default enabled cipher list might not
+contain any PSK cipher suite. In that case, desired PSK
+cipher suites must be enabled using \fI\%\-\-ciphers\fP option.
+The desired PSK cipher suite may be block listed by
+HTTP/2. To use those cipher suites with HTTP/2,
+consider to use \fI\%\-\-no\-http2\-cipher\-block\-list\fP option.
+But be aware its implications.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-client\-psk\-secrets=<PATH>
+Read PSK identity and secrets from <PATH>. This is used
+for backend connection. The each line of input file is
+formatted as <identity>:<hex\-secret>, where <identity>
+is PSK identity, and <hex\-secret> is secret in hex. An
+empty line, and line which starts with \(aq#\(aq are skipped.
+The first identity and secret pair encountered is used.
+The default enabled cipher list might not contain any
+PSK cipher suite. In that case, desired PSK cipher
+suites must be enabled using \fI\%\-\-client\-ciphers\fP option.
+The desired PSK cipher suite may be block listed by
+HTTP/2. To use those cipher suites with HTTP/2,
+consider to use \fI\%\-\-client\-no\-http2\-cipher\-block\-list\fP
+option. But be aware its implications.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-no\-postpone\-early\-data
+By default, except for QUIC connections, nghttpx
+postpones forwarding HTTP requests sent in early data,
+including those sent in partially in it, until TLS
+handshake finishes. If all backend server recognizes
+\(dqEarly\-Data\(dq header field, using this option makes
+nghttpx not postpone forwarding request and get full
+potential of 0\-RTT data.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-max\-early\-data=<SIZE>
+Sets the maximum amount of 0\-RTT data that server
+accepts.
+.sp
+Default: \fB16K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-tls\-ktls
+Enable ktls. For server, ktls is enable if
+\fI\%\-\-tls\-session\-cache\-memcached\fP is not configured.
+.UNINDENT
+.SS HTTP/2
+.INDENT 0.0
+.TP
+.B \-c, \-\-frontend\-http2\-max\-concurrent\-streams=<N>
+Set the maximum number of the concurrent streams in one
+frontend HTTP/2 session.
+.sp
+Default: \fB100\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-http2\-max\-concurrent\-streams=<N>
+Set the maximum number of the concurrent streams in one
+backend HTTP/2 session. This sets maximum number of
+concurrent opened pushed streams. The maximum number of
+concurrent requests are set by a remote server.
+.sp
+Default: \fB100\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-window\-size=<SIZE>
+Sets the per\-stream initial window size of HTTP/2
+frontend connection.
+.sp
+Default: \fB65535\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-connection\-window\-size=<SIZE>
+Sets the per\-connection window size of HTTP/2 frontend
+connection.
+.sp
+Default: \fB65535\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-http2\-window\-size=<SIZE>
+Sets the initial window size of HTTP/2 backend
+connection.
+.sp
+Default: \fB65535\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-http2\-connection\-window\-size=<SIZE>
+Sets the per\-connection window size of HTTP/2 backend
+connection.
+.sp
+Default: \fB2147483647\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-http2\-no\-cookie\-crumbling
+Don\(aqt crumble cookie header field.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-padding=<N>
+Add at most <N> bytes to a HTTP/2 frame payload as
+padding. Specify 0 to disable padding. This option is
+meant for debugging purpose and not intended to enhance
+protocol security.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-server\-push
+Disable HTTP/2 server push. Server push is supported by
+default mode and HTTP/2 frontend via Link header field.
+It is also supported if both frontend and backend are
+HTTP/2 in default mode. In this case, server push from
+backend session is relayed to frontend, and server push
+via Link header field is also supported.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-optimize\-write\-buffer\-size
+(Experimental) Enable write buffer size optimization in
+frontend HTTP/2 TLS connection. This optimization aims
+to reduce write buffer size so that it only contains
+bytes which can send immediately. This makes server
+more responsive to prioritized HTTP/2 stream because the
+buffering of lower priority stream is reduced. This
+option is only effective on recent Linux platform.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-optimize\-window\-size
+(Experimental) Automatically tune connection level
+window size of frontend HTTP/2 TLS connection. If this
+feature is enabled, connection window size starts with
+the default window size, 65535 bytes. nghttpx
+automatically adjusts connection window size based on
+TCP receiving window size. The maximum window size is
+capped by the value specified by
+\fI\%\-\-frontend\-http2\-connection\-window\-size\fP\&. Since the
+stream is subject to stream level window size, it should
+be adjusted using \fI\%\-\-frontend\-http2\-window\-size\fP option as
+well. This option is only effective on recent Linux
+platform.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-encoder\-dynamic\-table\-size=<SIZE>
+Specify the maximum dynamic table size of HPACK encoder
+in the frontend HTTP/2 connection. The decoder (client)
+specifies the maximum dynamic table size it accepts.
+Then the negotiated dynamic table size is the minimum of
+this option value and the value which client specified.
+.sp
+Default: \fB4K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-decoder\-dynamic\-table\-size=<SIZE>
+Specify the maximum dynamic table size of HPACK decoder
+in the frontend HTTP/2 connection.
+.sp
+Default: \fB4K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-http2\-encoder\-dynamic\-table\-size=<SIZE>
+Specify the maximum dynamic table size of HPACK encoder
+in the backend HTTP/2 connection. The decoder (backend)
+specifies the maximum dynamic table size it accepts.
+Then the negotiated dynamic table size is the minimum of
+this option value and the value which backend specified.
+.sp
+Default: \fB4K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-backend\-http2\-decoder\-dynamic\-table\-size=<SIZE>
+Specify the maximum dynamic table size of HPACK decoder
+in the backend HTTP/2 connection.
+.sp
+Default: \fB4K\fP
+.UNINDENT
+.SS Mode
+.INDENT 0.0
+.TP
+.B (default mode)
+Accept HTTP/2, and HTTP/1.1 over SSL/TLS. \(dqno\-tls\(dq
+parameter is used in \fI\%\-\-frontend\fP option, accept HTTP/2
+and HTTP/1.1 over cleartext TCP. The incoming HTTP/1.1
+connection can be upgraded to HTTP/2 through HTTP
+Upgrade.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-s, \-\-http2\-proxy
+Like default mode, but enable forward proxy. This is so
+called HTTP/2 proxy mode.
+.UNINDENT
+.SS Logging
+.INDENT 0.0
+.TP
+.B \-L, \-\-log\-level=<LEVEL>
+Set the severity level of log output. <LEVEL> must be
+one of INFO, NOTICE, WARN, ERROR and FATAL.
+.sp
+Default: \fBNOTICE\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-accesslog\-file=<PATH>
+Set path to write access log. To reopen file, send USR1
+signal to nghttpx.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-accesslog\-syslog
+Send access log to syslog. If this option is used,
+\fI\%\-\-accesslog\-file\fP option is ignored.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-accesslog\-format=<FORMAT>
+Specify format string for access log. The default
+format is combined format. The following variables are
+available:
+.INDENT 7.0
+.IP \(bu 2
+$remote_addr: client IP address.
+.IP \(bu 2
+$time_local: local time in Common Log format.
+.IP \(bu 2
+$time_iso8601: local time in ISO 8601 format.
+.IP \(bu 2
+$request: HTTP request line.
+.IP \(bu 2
+$status: HTTP response status code.
+.IP \(bu 2
+$body_bytes_sent: the number of bytes sent to client
+as response body.
+.IP \(bu 2
+$http_<VAR>: value of HTTP request header <VAR> where
+\(aq_\(aq in <VAR> is replaced with \(aq\-\(aq.
+.IP \(bu 2
+$remote_port: client port.
+.IP \(bu 2
+$server_port: server port.
+.IP \(bu 2
+$request_time: request processing time in seconds with
+milliseconds resolution.
+.IP \(bu 2
+$pid: PID of the running process.
+.IP \(bu 2
+$alpn: ALPN identifier of the protocol which generates
+the response. For HTTP/1, ALPN is always http/1.1,
+regardless of minor version.
+.IP \(bu 2
+$tls_cipher: cipher used for SSL/TLS connection.
+.IP \(bu 2
+$tls_client_fingerprint_sha256: SHA\-256 fingerprint of
+client certificate.
+.IP \(bu 2
+$tls_client_fingerprint_sha1: SHA\-1 fingerprint of
+client certificate.
+.IP \(bu 2
+$tls_client_subject_name: subject name in client
+certificate.
+.IP \(bu 2
+$tls_client_issuer_name: issuer name in client
+certificate.
+.IP \(bu 2
+$tls_client_serial: serial number in client
+certificate.
+.IP \(bu 2
+$tls_protocol: protocol for SSL/TLS connection.
+.IP \(bu 2
+$tls_session_id: session ID for SSL/TLS connection.
+.IP \(bu 2
+$tls_session_reused: \(dqr\(dq if SSL/TLS session was
+reused. Otherwise, \(dq.\(dq
+.IP \(bu 2
+$tls_sni: SNI server name for SSL/TLS connection.
+.IP \(bu 2
+$backend_host: backend host used to fulfill the
+request. \(dq\-\(dq if backend host is not available.
+.IP \(bu 2
+$backend_port: backend port used to fulfill the
+request. \(dq\-\(dq if backend host is not available.
+.IP \(bu 2
+$method: HTTP method
+.IP \(bu 2
+$path: Request path including query. For CONNECT
+request, authority is recorded.
+.IP \(bu 2
+$path_without_query: $path up to the first \(aq?\(aq
+character. For CONNECT request, authority is
+recorded.
+.IP \(bu 2
+$protocol_version: HTTP version (e.g., HTTP/1.1,
+HTTP/2)
+.UNINDENT
+.sp
+The variable can be enclosed by \(dq{\(dq and \(dq}\(dq for
+disambiguation (e.g., ${remote_addr}).
+.sp
+Default: \fB$remote_addr \- \- [$time_local] \(dq$request\(dq $status $body_bytes_sent \(dq$http_referer\(dq \(dq$http_user_agent\(dq\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-accesslog\-write\-early
+Write access log when response header fields are
+received from backend rather than when request
+transaction finishes.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-errorlog\-file=<PATH>
+Set path to write error log. To reopen file, send USR1
+signal to nghttpx. stderr will be redirected to the
+error log file unless \fI\%\-\-errorlog\-syslog\fP is used.
+.sp
+Default: \fB/dev/stderr\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-errorlog\-syslog
+Send error log to syslog. If this option is used,
+\fI\%\-\-errorlog\-file\fP option is ignored.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-syslog\-facility=<FACILITY>
+Set syslog facility to <FACILITY>.
+.sp
+Default: \fBdaemon\fP
+.UNINDENT
+.SS HTTP
+.INDENT 0.0
+.TP
+.B \-\-add\-x\-forwarded\-for
+Append X\-Forwarded\-For header field to the downstream
+request.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-strip\-incoming\-x\-forwarded\-for
+Strip X\-Forwarded\-For header field from inbound client
+requests.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-add\-x\-forwarded\-proto
+Don\(aqt append additional X\-Forwarded\-Proto header field
+to the backend request. If inbound client sets
+X\-Forwarded\-Proto, and
+\fI\%\-\-no\-strip\-incoming\-x\-forwarded\-proto\fP option is used,
+they are passed to the backend.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-strip\-incoming\-x\-forwarded\-proto
+Don\(aqt strip X\-Forwarded\-Proto header field from inbound
+client requests.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-add\-forwarded=<LIST>
+Append RFC 7239 Forwarded header field with parameters
+specified in comma delimited list <LIST>. The supported
+parameters are \(dqby\(dq, \(dqfor\(dq, \(dqhost\(dq, and \(dqproto\(dq. By
+default, the value of \(dqby\(dq and \(dqfor\(dq parameters are
+obfuscated string. See \fI\%\-\-forwarded\-by\fP and
+\fI\%\-\-forwarded\-for\fP options respectively. Note that nghttpx
+does not translate non\-standard X\-Forwarded\-* header
+fields into Forwarded header field, and vice versa.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-strip\-incoming\-forwarded
+Strip Forwarded header field from inbound client
+requests.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-forwarded\-by=(obfuscated|ip|<VALUE>)
+Specify the parameter value sent out with \(dqby\(dq parameter
+of Forwarded header field. If \(dqobfuscated\(dq is given,
+the string is randomly generated at startup. If \(dqip\(dq is
+given, the interface address of the connection,
+including port number, is sent with \(dqby\(dq parameter. In
+case of UNIX domain socket, \(dqlocalhost\(dq is used instead
+of address and port. User can also specify the static
+obfuscated string. The limitation is that it must start
+with \(dq_\(dq, and only consists of character set
+[A\-Za\-z0\-9._\-], as described in RFC 7239.
+.sp
+Default: \fBobfuscated\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-forwarded\-for=(obfuscated|ip)
+Specify the parameter value sent out with \(dqfor\(dq
+parameter of Forwarded header field. If \(dqobfuscated\(dq is
+given, the string is randomly generated for each client
+connection. If \(dqip\(dq is given, the remote client address
+of the connection, without port number, is sent with
+\(dqfor\(dq parameter. In case of UNIX domain socket,
+\(dqlocalhost\(dq is used instead of address.
+.sp
+Default: \fBobfuscated\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-via
+Don\(aqt append to Via header field. If Via header field
+is received, it is left unaltered.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-strip\-incoming\-early\-data
+Don\(aqt strip Early\-Data header field from inbound client
+requests.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-location\-rewrite
+Don\(aqt rewrite location header field in default mode.
+When \fI\%\-\-http2\-proxy\fP is used, location header field will
+not be altered regardless of this option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-host\-rewrite
+Rewrite host and :authority header fields in default
+mode. When \fI\%\-\-http2\-proxy\fP is used, these headers will
+not be altered regardless of this option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
+Specify protocol ID, port, host and origin of
+alternative service. <HOST>, <ORIGIN> and <PARAMS> are
+optional. Empty <HOST> and <ORIGIN> are allowed and
+they are treated as nothing is specified. They are
+advertised in alt\-svc header field only in HTTP/1.1
+frontend. This option can be used multiple times to
+specify multiple alternative services.
+Example: \fI\%\-\-altsvc\fP=\(dqh2,443,,,ma=3600; persist=1\(dq
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-http2\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
+Just like \fI\%\-\-altsvc\fP option, but this altsvc is only sent
+in HTTP/2 frontend.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-add\-request\-header=<HEADER>
+Specify additional header field to add to request header
+set. The field name must be lowercase. This option
+just appends header field and won\(aqt replace anything
+already set. This option can be used several times to
+specify multiple header fields.
+Example: \fI\%\-\-add\-request\-header\fP=\(dqfoo: bar\(dq
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-add\-response\-header=<HEADER>
+Specify additional header field to add to response
+header set. The field name must be lowercase. This
+option just appends header field and won\(aqt replace
+anything already set. This option can be used several
+times to specify multiple header fields.
+Example: \fI\%\-\-add\-response\-header\fP=\(dqfoo: bar\(dq
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-request\-header\-field\-buffer=<SIZE>
+Set maximum buffer size for incoming HTTP request header
+field list. This is the sum of header name and value in
+bytes. If trailer fields exist, they are counted
+towards this number.
+.sp
+Default: \fB64K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-max\-request\-header\-fields=<N>
+Set maximum number of incoming HTTP request header
+fields. If trailer fields exist, they are counted
+towards this number.
+.sp
+Default: \fB100\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-response\-header\-field\-buffer=<SIZE>
+Set maximum buffer size for incoming HTTP response
+header field list. This is the sum of header name and
+value in bytes. If trailer fields exist, they are
+counted towards this number.
+.sp
+Default: \fB64K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-max\-response\-header\-fields=<N>
+Set maximum number of incoming HTTP response header
+fields. If trailer fields exist, they are counted
+towards this number.
+.sp
+Default: \fB500\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-error\-page=(<CODE>|*)=<PATH>
+Set file path to custom error page served when nghttpx
+originally generates HTTP error status code <CODE>.
+<CODE> must be greater than or equal to 400, and at most
+599. If \(dq*\(dq is used instead of <CODE>, it matches all
+HTTP status code. If error status code comes from
+backend server, the custom error pages are not used.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-server\-name=<NAME>
+Change server response header field value to <NAME>.
+.sp
+Default: \fBnghttpx\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-server\-rewrite
+Don\(aqt rewrite server header field in default mode. When
+\fI\%\-\-http2\-proxy\fP is used, these headers will not be altered
+regardless of this option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-redirect\-https\-port=<PORT>
+Specify the port number which appears in Location header
+field when redirect to HTTPS URI is made due to
+\(dqredirect\-if\-not\-tls\(dq parameter in \fI\%\-\-backend\fP option.
+.sp
+Default: \fB443\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-require\-http\-scheme
+Always require http or https scheme in HTTP request. It
+also requires that https scheme must be used for an
+encrypted connection. Otherwise, http scheme must be
+used. This option is recommended for a server
+deployment which directly faces clients and the services
+it provides only require http or https scheme.
+.UNINDENT
+.SS API
+.INDENT 0.0
+.TP
+.B \-\-api\-max\-request\-body=<SIZE>
+Set the maximum size of request body for API request.
+.sp
+Default: \fB32M\fP
+.UNINDENT
+.SS DNS
+.INDENT 0.0
+.TP
+.B \-\-dns\-cache\-timeout=<DURATION>
+Set duration that cached DNS results remain valid. Note
+that nghttpx caches the unsuccessful results as well.
+.sp
+Default: \fB10s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-dns\-lookup\-timeout=<DURATION>
+Set timeout that DNS server is given to respond to the
+initial DNS query. For the 2nd and later queries,
+server is given time based on this timeout, and it is
+scaled linearly.
+.sp
+Default: \fB5s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-dns\-max\-try=<N>
+Set the number of DNS query before nghttpx gives up name
+lookup.
+.sp
+Default: \fB2\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-max\-requests=<N>
+The number of requests that single frontend connection
+can process. For HTTP/2, this is the number of streams
+in one HTTP/2 connection. For HTTP/1, this is the
+number of keep alive requests. This is hint to nghttpx,
+and it may allow additional few requests. The default
+value is unlimited.
+.UNINDENT
+.SS Debug
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-dump\-request\-header=<PATH>
+Dumps request headers received by HTTP/2 frontend to the
+file denoted in <PATH>. The output is done in HTTP/1
+header field format and each header block is followed by
+an empty line. This option is not thread safe and MUST
+NOT be used with option \fI\%\-n\fP<N>, where <N> >= 2.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http2\-dump\-response\-header=<PATH>
+Dumps response headers sent from HTTP/2 frontend to the
+file denoted in <PATH>. The output is done in HTTP/1
+header field format and each header block is followed by
+an empty line. This option is not thread safe and MUST
+NOT be used with option \fI\%\-n\fP<N>, where <N> >= 2.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-o, \-\-frontend\-frame\-debug
+Print HTTP/2 frames in frontend to stderr. This option
+is not thread safe and MUST NOT be used with option
+\fI\%\-n\fP=N, where N >= 2.
+.UNINDENT
+.SS Process
+.INDENT 0.0
+.TP
+.B \-D, \-\-daemon
+Run in a background. If \fI\%\-D\fP is used, the current working
+directory is changed to \(aq\fI/\fP\(aq.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-pid\-file=<PATH>
+Set path to save PID of this program.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-user=<USER>
+Run this program as <USER>. This option is intended to
+be used to drop root privileges.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-single\-process
+Run this program in a single process mode for debugging
+purpose. Without this option, nghttpx creates at least
+2 processes: main and worker processes. If this option
+is used, main and worker are unified into a single
+process. nghttpx still spawns additional process if
+neverbleed is used. In the single process mode, the
+signal handling feature is disabled.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-max\-worker\-processes=<N>
+The maximum number of worker processes. nghttpx spawns
+new worker process when it reloads its configuration.
+The previous worker process enters graceful termination
+period and will terminate when it finishes handling the
+existing connections. However, if reloading
+configurations happen very frequently, the worker
+processes might be piled up if they take a bit long time
+to finish the existing connections. With this option,
+if the number of worker processes exceeds the given
+value, the oldest worker process is terminated
+immediately. Specifying 0 means no limit and it is the
+default behaviour.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-worker\-process\-grace\-shutdown\-period=<DURATION>
+Maximum period for a worker process to terminate
+gracefully. When a worker process enters in graceful
+shutdown period (e.g., when nghttpx reloads its
+configuration) and it does not finish handling the
+existing connections in the given period of time, it is
+immediately terminated. Specifying 0 means no limit and
+it is the default behaviour.
+.UNINDENT
+.SS Scripting
+.INDENT 0.0
+.TP
+.B \-\-mruby\-file=<PATH>
+Set mruby script file
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ignore\-per\-pattern\-mruby\-error
+Ignore mruby compile error for per\-pattern mruby script
+file. If error occurred, it is treated as if no mruby
+file were specified for the pattern.
+.UNINDENT
+.SS HTTP/3 and QUIC
+.INDENT 0.0
+.TP
+.B \-\-frontend\-quic\-idle\-timeout=<DURATION>
+Specify an idle timeout for QUIC connection.
+.sp
+Default: \fB30s\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-quic\-debug\-log
+Output QUIC debug log to \fI/dev/stderr.\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-quic\-bpf\-program\-file=<PATH>
+Specify a path to eBPF program file reuseport_kern.o to
+direct an incoming QUIC UDP datagram to a correct
+socket.
+.sp
+Default: \fB/usr/local/lib/nghttp2/reuseport_kern.o\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-quic\-early\-data
+Enable early data on frontend QUIC connections. nghttpx
+sends \(dqEarly\-Data\(dq header field to a backend server if a
+request is received in early data and handshake has not
+finished. All backend servers should deal with possibly
+replayed requests.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-quic\-qlog\-dir=<DIR>
+Specify a directory where a qlog file is written for
+frontend QUIC connections. A qlog file is created per
+each QUIC connection. The file name is ISO8601 basic
+format, followed by \(dq\-\(dq, server Source Connection ID and
+\(dq.sqlog\(dq.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-quic\-require\-token
+Require an address validation token for a frontend QUIC
+connection. Server sends a token in Retry packet or
+NEW_TOKEN frame in the previous connection.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-quic\-congestion\-controller=<CC>
+Specify a congestion controller algorithm for a frontend
+QUIC connection. <CC> should be either \(dqcubic\(dq or
+\(dqbbr\(dq.
+.sp
+Default: \fBcubic\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-quic\-secret\-file=<PATH>
+Path to file that contains secure random data to be used
+as QUIC keying materials. It is used to derive keys for
+encrypting tokens and Connection IDs. It is not used to
+encrypt QUIC packets. Each line of this file must
+contain exactly 136 bytes hex\-encoded string (when
+decoded the byte string is 68 bytes long). The first 2
+bits of decoded byte string are used to identify the
+keying material. An empty line or a line which starts
+\(aq#\(aq is ignored. The file can contain more than one
+keying materials. Because the identifier is 2 bits, at
+most 4 keying materials are read and the remaining data
+is discarded. The first keying material in the file is
+primarily used for encryption and decryption for new
+connection. The other ones are used to decrypt data for
+the existing connections. Specifying multiple keying
+materials enables key rotation. Please note that key
+rotation does not occur automatically. User should
+update files or change options values and restart
+nghttpx gracefully. If opening or reading given file
+fails, all loaded keying materials are discarded and it
+is treated as if none of this option is given. If this
+option is not given or an error occurred while opening
+or reading a file, a keying material is generated
+internally on startup and reload.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-quic\-server\-id=<HEXSTRING>
+Specify server ID encoded in Connection ID to identify
+this particular server instance. Connection ID is
+encrypted and this part is not visible in public. It
+must be 4 bytes long and must be encoded in hex string
+(which is 8 bytes long). If this option is omitted, a
+random server ID is generated on startup and
+configuration reload.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-quic\-initial\-rtt=<DURATION>
+Specify the initial RTT of the frontend QUIC connection.
+.sp
+Default: \fB333ms\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-quic\-bpf
+Disable eBPF.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http3\-window\-size=<SIZE>
+Sets the per\-stream initial window size of HTTP/3
+frontend connection.
+.sp
+Default: \fB256K\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http3\-connection\-window\-size=<SIZE>
+Sets the per\-connection window size of HTTP/3 frontend
+connection.
+.sp
+Default: \fB1M\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http3\-max\-window\-size=<SIZE>
+Sets the maximum per\-stream window size of HTTP/3
+frontend connection. The window size is adjusted based
+on the receiving rate of stream data. The initial value
+is the value specified by \fI\%\-\-frontend\-http3\-window\-size\fP
+and the window size grows up to <SIZE> bytes.
+.sp
+Default: \fB6M\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http3\-max\-connection\-window\-size=<SIZE>
+Sets the maximum per\-connection window size of HTTP/3
+frontend connection. The window size is adjusted based
+on the receiving rate of stream data. The initial value
+is the value specified by
+\fI\%\-\-frontend\-http3\-connection\-window\-size\fP and the window
+size grows up to <SIZE> bytes.
+.sp
+Default: \fB8M\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-frontend\-http3\-max\-concurrent\-streams=<N>
+Set the maximum number of the concurrent streams in one
+frontend HTTP/3 connection.
+.sp
+Default: \fB100\fP
+.UNINDENT
+.SS Misc
+.INDENT 0.0
+.TP
+.B \-\-conf=<PATH>
+Load configuration from <PATH>. Please note that
+nghttpx always tries to read the default configuration
+file if \fI\%\-\-conf\fP is not given.
+.sp
+Default: \fB/etc/nghttpx/nghttpx.conf\fP
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-include=<PATH>
+Load additional configurations from <PATH>. File <PATH>
+is read when configuration parser encountered this
+option. This option can be used multiple times, or even
+recursively.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-v, \-\-version
+Print version and exit.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-h, \-\-help
+Print this help and exit.
+.UNINDENT
+.sp
+The <SIZE> argument is an integer and an optional unit (e.g., 10K is
+10 * 1024). Units are K, M and G (powers of 1024).
+.sp
+The <DURATION> argument is an integer and an optional unit (e.g., 1s
+is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
+(hours, minutes, seconds and milliseconds, respectively). If a unit
+is omitted, a second is used as unit.
+.SH FILES
+.INDENT 0.0
+.TP
+.B \fI/etc/nghttpx/nghttpx.conf\fP
+The default configuration file path nghttpx searches at startup.
+The configuration file path can be changed using \fI\%\-\-conf\fP
+option.
+.sp
+Those lines which are staring \fB#\fP are treated as comment.
+.sp
+The option name in the configuration file is the long command\-line
+option name with leading \fB\-\-\fP stripped (e.g., \fBfrontend\fP). Put
+\fB=\fP between option name and value. Don\(aqt put extra leading or
+trailing spaces.
+.sp
+When specifying arguments including characters which have special
+meaning to a shell, we usually use quotes so that shell does not
+interpret them. When writing this configuration file, quotes for
+this purpose must not be used. For example, specify additional
+request header field, do this:
+.INDENT 7.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+add\-request\-header=foo: bar
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+instead of:
+.INDENT 7.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+add\-request\-header=\(dqfoo: bar\(dq
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+The options which do not take argument in the command\-line \fItake\fP
+argument in the configuration file. Specify \fByes\fP as an argument
+(e.g., \fBhttp2\-proxy=yes\fP). If other string is given, it is
+ignored.
+.sp
+To specify private key and certificate file which are given as
+positional arguments in command\-line, use \fBprivate\-key\-file\fP and
+\fBcertificate\-file\fP\&.
+.sp
+\fI\%\-\-conf\fP option cannot be used in the configuration file and
+will be ignored if specified.
+.TP
+.B Error log
+Error log is written to stderr by default. It can be configured
+using \fI\%\-\-errorlog\-file\fP\&. The format of log message is as
+follows:
+.sp
+<datetime> <main\-pid> <current\-pid> <thread\-id> <level> (<filename>:<line>) <msg>
+.INDENT 7.0
+.TP
+.B <datetime>
+It is a combination of date and time when the log is written. It
+is in ISO 8601 format.
+.TP
+.B <main\-pid>
+It is a main process ID.
+.TP
+.B <current\-pid>
+It is a process ID which writes this log.
+.TP
+.B <thread\-id>
+It is a thread ID which writes this log. It would be unique
+within <current\-pid>.
+.TP
+.B <filename> and <line>
+They are source file name, and line number which produce this log.
+.TP
+.B <msg>
+It is a log message body.
+.UNINDENT
+.UNINDENT
+.SH SIGNALS
+.INDENT 0.0
+.TP
+.B SIGQUIT
+Shutdown gracefully. First accept pending connections and stop
+accepting connection. After all connections are handled, nghttpx
+exits.
+.TP
+.B SIGHUP
+Reload configuration file given in \fI\%\-\-conf\fP\&.
+.TP
+.B SIGUSR1
+Reopen log files.
+.UNINDENT
+.sp
+SIGUSR2
+.INDENT 0.0
+.INDENT 3.5
+Fork and execute nghttpx. It will execute the binary in the same
+path with same command\-line arguments and environment variables. As
+of nghttpx version 1.20.0, the new main process sends SIGQUIT to the
+original main process when it is ready to serve requests. For the
+earlier versions of nghttpx, user has to send SIGQUIT to the
+original main process.
+.sp
+The difference between SIGUSR2 (+ SIGQUIT) and SIGHUP is that former
+is usually used to execute new binary, and the main process is newly
+spawned. On the other hand, the latter just reloads configuration
+file, and the same main process continues to exist.
+.UNINDENT
+.UNINDENT
+.sp
+\fBNOTE:\fP
+.INDENT 0.0
+.INDENT 3.5
+nghttpx consists of multiple processes: one process for processing
+these signals, and another one for processing requests. The former
+spawns the latter. The former is called main process, and the
+latter is called worker process. If neverbleed is enabled, the
+worker process spawns neverbleed daemon process which does RSA key
+processing. The above signal must be sent to the main process. If
+the other processes received one of them, it is ignored. This
+behaviour of these processes may change in the future release. In
+other words, in the future release, the processes other than main
+process may terminate upon the reception of these signals.
+Therefore these signals should not be sent to the processes other
+than main process.
+.UNINDENT
+.UNINDENT
+.SH SERVER PUSH
+.sp
+nghttpx supports HTTP/2 server push in default mode with Link header
+field. nghttpx looks for Link header field (\fI\%RFC 5988\fP) in response headers from
+backend server and extracts URI\-reference with parameter
+\fBrel=preload\fP (see \fI\%preload\fP)
+and pushes those URIs to the frontend client. Here is a sample Link
+header field to initiate server push:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+Link: </fonts/font.woff>; rel=preload
+Link: </css/theme.css>; rel=preload
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Currently, the following restriction is applied for server push:
+.INDENT 0.0
+.IP 1. 3
+The associated stream must have method \(dqGET\(dq or \(dqPOST\(dq. The
+associated stream\(aqs status code must be 200.
+.UNINDENT
+.sp
+This limitation may be loosened in the future release.
+.sp
+nghttpx also supports server push if both frontend and backend are
+HTTP/2 in default mode. In this case, in addition to server push via
+Link header field, server push from backend is forwarded to frontend
+HTTP/2 session.
+.sp
+HTTP/2 server push will be disabled if \fI\%\-\-http2\-proxy\fP is
+used.
+.SH UNIX DOMAIN SOCKET
+.sp
+nghttpx supports UNIX domain socket with a filename for both frontend
+and backend connections.
+.sp
+Please note that current nghttpx implementation does not delete a
+socket with a filename. And on start up, if nghttpx detects that the
+specified socket already exists in the file system, nghttpx first
+deletes it. However, if SIGUSR2 is used to execute new binary and
+both old and new configurations use same filename, new binary does not
+delete the socket and continues to use it.
+.SH OCSP STAPLING
+.sp
+OCSP query is done using external Python script
+\fBfetch\-ocsp\-response\fP, which has been originally developed in Perl
+as part of h2o project (\fI\%https://github.com/h2o/h2o\fP), and was
+translated into Python.
+.sp
+The script file is usually installed under
+\fB$(prefix)/share/nghttp2/\fP directory. The actual path to script can
+be customized using \fI\%\-\-fetch\-ocsp\-response\-file\fP option.
+.sp
+If OCSP query is failed, previous OCSP response, if any, is continued
+to be used.
+.sp
+\fI\%\-\-fetch\-ocsp\-response\-file\fP option provides wide range of
+possibility to manage OCSP response. It can take an arbitrary script
+or executable. The requirement is that it supports the command\-line
+interface of \fBfetch\-ocsp\-response\fP script, and it must return a
+valid DER encoded OCSP response on success. It must return exit code
+0 on success, and 75 for temporary error, and the other error code for
+generic failure. For large cluster of servers, it is not efficient
+for each server to perform OCSP query using \fBfetch\-ocsp\-response\fP\&.
+Instead, you can retrieve OCSP response in some way, and store it in a
+disk or a shared database. Then specify a program in
+\fI\%\-\-fetch\-ocsp\-response\-file\fP to fetch it from those stores.
+This could provide a way to share the OCSP response between fleet of
+servers, and also any OCSP query strategy can be applied which may be
+beyond the ability of nghttpx itself or \fBfetch\-ocsp\-response\fP
+script.
+.SH TLS SESSION RESUMPTION
+.sp
+nghttpx supports TLS session resumption through both session ID and
+session ticket.
+.SS SESSION ID RESUMPTION
+.sp
+By default, session ID is shared by all worker threads.
+.sp
+If \fI\%\-\-tls\-session\-cache\-memcached\fP is given, nghttpx will
+insert serialized session data to memcached with
+\fBnghttpx:tls\-session\-cache:\fP + lowercase hex string of session ID
+as a memcached entry key, with expiry time 12 hours. Session timeout
+is set to 12 hours.
+.sp
+By default, connections to memcached server are not encrypted. To
+enable encryption, use \fBtls\fP keyword in
+\fI\%\-\-tls\-session\-cache\-memcached\fP option.
+.SS TLS SESSION TICKET RESUMPTION
+.sp
+By default, session ticket is shared by all worker threads. The
+automatic key rotation is also enabled by default. Every an hour, new
+encryption key is generated, and previous encryption key becomes
+decryption only key. We set session timeout to 12 hours, and thus we
+keep at most 12 keys.
+.sp
+If \fI\%\-\-tls\-ticket\-key\-memcached\fP is given, encryption keys are
+retrieved from memcached. nghttpx just reads keys from memcached; one
+has to deploy key generator program to update keys frequently (e.g.,
+every 1 hour). The example key generator tlsticketupdate.go is
+available under contrib directory in nghttp2 archive. The memcached
+entry key is \fBnghttpx:tls\-ticket\-key\fP\&. The data format stored in
+memcached is the binary format described below:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
++\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
+| VERSION (4) |LEN (2)|KEY(48 or 80) ...
++\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
+ ^ |
+ | |
+ +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
+ (LEN, KEY) pair can be repeated
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+All numbers in the above figure is bytes. All integer fields are
+network byte order.
+.sp
+First 4 bytes integer VERSION field, which must be 1. The 2 bytes
+integer LEN field gives the length of following KEY field, which
+contains key. If \fI\%\-\-tls\-ticket\-key\-cipher\fP=aes\-128\-cbc is
+used, LEN must be 48. If
+\fI\%\-\-tls\-ticket\-key\-cipher\fP=aes\-256\-cbc is used, LEN must be
+80. LEN and KEY pair can be repeated multiple times to store multiple
+keys. The key appeared first is used as encryption key. All the
+remaining keys are used as decryption only.
+.sp
+By default, connections to memcached server are not encrypted. To
+enable encryption, use \fBtls\fP keyword in
+\fI\%\-\-tls\-ticket\-key\-memcached\fP option.
+.sp
+If \fI\%\-\-tls\-ticket\-key\-file\fP is given, encryption key is read
+from the given file. In this case, nghttpx does not rotate key
+automatically. To rotate key, one has to restart nghttpx (see
+SIGNALS).
+.SH CERTIFICATE TRANSPARENCY
+.sp
+nghttpx supports TLS \fBsigned_certificate_timestamp\fP extension (\fI\%RFC
+6962\fP). The relevant options
+are \fI\%\-\-tls\-sct\-dir\fP and \fBsct\-dir\fP parameter in
+\fI\%\-\-subcert\fP\&. They takes a directory, and nghttpx reads all
+files whose extension is \fB\&.sct\fP under the directory. The \fB*.sct\fP
+files are encoded as \fBSignedCertificateTimestamp\fP struct described
+in \fI\%section 3.2 of RFC 69662\fP\&. This format is
+the same one used by \fI\%nginx\-ct\fP and \fI\%mod_ssl_ct\fP\&.
+\fI\%ct\-submit\fP can be
+used to submit certificates to log servers, and obtain the
+\fBSignedCertificateTimestamp\fP struct which can be used with nghttpx.
+.SH MRUBY SCRIPTING
+.sp
+\fBWARNING:\fP
+.INDENT 0.0
+.INDENT 3.5
+The current mruby extension API is experimental and not frozen. The
+API is subject to change in the future release.
+.UNINDENT
+.UNINDENT
+.sp
+\fBWARNING:\fP
+.INDENT 0.0
+.INDENT 3.5
+Almost all string value returned from method, or attribute is a
+fresh new mruby string, which involves memory allocation, and
+copies. Therefore, it is strongly recommended to store a return
+value in a local variable, and use it, instead of calling method or
+accessing attribute repeatedly.
+.UNINDENT
+.UNINDENT
+.sp
+nghttpx allows users to extend its capability using mruby scripts.
+nghttpx has 2 hook points to execute mruby script: request phase and
+response phase. The request phase hook is invoked after all request
+header fields are received from client. The response phase hook is
+invoked after all response header fields are received from backend
+server. These hooks allows users to modify header fields, or common
+HTTP variables, like authority or request path, and even return custom
+response without forwarding request to backend servers.
+.sp
+There are 2 levels of mruby script invocations: global and
+per\-pattern. The global mruby script is set by \fI\%\-\-mruby\-file\fP
+option and is called for all requests. The per\-pattern mruby script
+is set by \(dqmruby\(dq parameter in \fI\%\-b\fP option. It is invoked for
+a request which matches the particular pattern. The order of hook
+invocation is: global request phase hook, per\-pattern request phase
+hook, per\-pattern response phase hook, and finally global response
+phase hook. If a hook returns a response, any later hooks are not
+invoked. The global request hook is invoked before the pattern
+matching is made and changing request path may affect the pattern
+matching.
+.sp
+Please note that request and response hooks of per\-pattern mruby
+script for a single request might not come from the same script. This
+might happen after a request hook is executed, backend failed for some
+reason, and at the same time, backend configuration is replaced by API
+request, and then the request uses new configuration on retry. The
+response hook from new configuration, if it is specified, will be
+invoked.
+.sp
+The all mruby script will be evaluated once per thread on startup, and
+it must instantiate object and evaluate it as the return value (e.g.,
+\fBApp.new\fP). This object is called app object. If app object
+defines \fBon_req\fP method, it is called with \fI\%Nghttpx::Env\fP
+object on request hook. Similarly, if app object defines \fBon_resp\fP
+method, it is called with \fI\%Nghttpx::Env\fP object on response
+hook. For each method invocation, user can can access
+\fI\%Nghttpx::Request\fP and \fI\%Nghttpx::Response\fP objects
+via \fI\%Nghttpx::Env#req\fP and \fI\%Nghttpx::Env#resp\fP
+respectively.
+.INDENT 0.0
+.TP
+.B Nghttpx::REQUEST_PHASE
+Constant to represent request phase.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B Nghttpx::RESPONSE_PHASE
+Constant to represent response phase.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B class Nghttpx::Env
+Object to represent current request specific context.
+.INDENT 7.0
+.TP
+.B attribute [R] req
+Return \fI\%Request\fP object.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] resp
+Return \fI\%Response\fP object.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] ctx
+Return Ruby hash object. It persists until request finishes.
+So values set in request phase hook can be retrieved in
+response phase hook.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] phase
+Return the current phase.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] remote_addr
+Return IP address of a remote client. If connection is made
+via UNIX domain socket, this returns the string \(dqlocalhost\(dq.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] server_addr
+Return address of server that accepted the connection. This
+is a string which specified in \fI\%\-\-frontend\fP option,
+excluding port number, and not a resolved IP address. For
+UNIX domain socket, this is a path to UNIX domain socket.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] server_port
+Return port number of the server frontend which accepted the
+connection from client.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_used
+Return true if TLS is used on the connection.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_sni
+Return the TLS SNI value which client sent in this connection.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_client_fingerprint_sha256
+Return the SHA\-256 fingerprint of a client certificate.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_client_fingerprint_sha1
+Return the SHA\-1 fingerprint of a client certificate.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_client_issuer_name
+Return the issuer name of a client certificate.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_client_subject_name
+Return the subject name of a client certificate.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_client_serial
+Return the serial number of a client certificate.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_client_not_before
+Return the start date of a client certificate in seconds since
+the epoch.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_client_not_after
+Return the end date of a client certificate in seconds since
+the epoch.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_cipher
+Return a TLS cipher negotiated in this connection.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_protocol
+Return a TLS protocol version negotiated in this connection.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_session_id
+Return a session ID for this connection in hex string.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_session_reused
+Return true if, and only if a SSL/TLS session is reused.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] alpn
+Return ALPN identifier negotiated in this connection.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] tls_handshake_finished
+Return true if SSL/TLS handshake has finished. If it returns
+false in the request phase hook, the request is received in
+TLSv1.3 early data (0\-RTT) and might be vulnerable to the
+replay attack. nghttpx will send Early\-Data header field to
+backend servers to indicate this.
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.TP
+.B class Nghttpx::Request
+Object to represent request from client. The modification to
+Request object is allowed only in request phase hook.
+.INDENT 7.0
+.TP
+.B attribute [R] http_version_major
+Return HTTP major version.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] http_version_minor
+Return HTTP minor version.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R/W] method
+HTTP method. On assignment, copy of given value is assigned.
+We don\(aqt accept arbitrary method name. We will document them
+later, but well known methods, like GET, PUT and POST, are all
+supported.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R/W] authority
+Authority (i.e., example.org), including optional port
+component . On assignment, copy of given value is assigned.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R/W] scheme
+Scheme (i.e., http, https). On assignment, copy of given
+value is assigned.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R/W] path
+Request path, including query component (i.e., /index.html).
+On assignment, copy of given value is assigned. The path does
+not include authority component of URI. This may include
+query component. nghttpx makes certain normalization for
+path. It decodes percent\-encoding for unreserved characters
+(see \fI\%https://tools.ietf.org/html/rfc3986#section\-2.3\fP), and
+resolves \(dq..\(dq and \(dq.\(dq. But it may leave characters which
+should be percent\-encoded as is. So be careful when comparing
+path against desired string.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] headers
+Return Ruby hash containing copy of request header fields.
+Changing values in returned hash does not change request
+header fields actually used in request processing. Use
+\fI\%Nghttpx::Request#add_header\fP or
+\fI\%Nghttpx::Request#set_header\fP to change request
+header fields.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B add_header(key, value)
+Add header entry associated with key. The value can be single
+string or array of string. It does not replace any existing
+values associated with key.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B set_header(key, value)
+Set header entry associated with key. The value can be single
+string or array of string. It replaces any existing values
+associated with key.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B clear_headers()
+Clear all existing request header fields.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B push(uri)
+Initiate to push resource identified by \fIuri\fP\&. Only HTTP/2
+protocol supports this feature. For the other protocols, this
+method is noop. \fIuri\fP can be absolute URI, absolute path or
+relative path to the current request. For absolute or
+relative path, scheme and authority are inherited from the
+current request. Currently, method is always GET. nghttpx
+will issue request to backend servers to fulfill this request.
+The request and response phase hooks will be called for pushed
+resource as well.
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.TP
+.B class Nghttpx::Response
+Object to represent response from backend server.
+.INDENT 7.0
+.TP
+.B attribute [R] http_version_major
+Return HTTP major version.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] http_version_minor
+Return HTTP minor version.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R/W] status
+HTTP status code. It must be in the range [200, 999],
+inclusive. The non\-final status code is not supported in
+mruby scripting at the moment.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B attribute [R] headers
+Return Ruby hash containing copy of response header fields.
+Changing values in returned hash does not change response
+header fields actually used in response processing. Use
+\fI\%Nghttpx::Response#add_header\fP or
+\fI\%Nghttpx::Response#set_header\fP to change response
+header fields.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B add_header(key, value)
+Add header entry associated with key. The value can be single
+string or array of string. It does not replace any existing
+values associated with key.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B set_header(key, value)
+Set header entry associated with key. The value can be single
+string or array of string. It replaces any existing values
+associated with key.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B clear_headers()
+Clear all existing response header fields.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B return(body)
+Return custom response \fIbody\fP to a client. When this method
+is called in request phase hook, the request is not forwarded
+to the backend, and response phase hook for this request will
+not be invoked. When this method is called in response phase
+hook, response from backend server is canceled and discarded.
+The status code and response header fields should be set
+before using this method. To set status code, use
+\fI\%Nghttpx::Response#status\fP\&. If status code is not
+set, 200 is used. To set response header fields,
+\fI\%Nghttpx::Response#add_header\fP and
+\fI\%Nghttpx::Response#set_header\fP\&. When this method is
+invoked in response phase hook, the response headers are
+filled with the ones received from backend server. To send
+completely custom header fields, first call
+\fI\%Nghttpx::Response#clear_headers\fP to erase all
+existing header fields, and then add required header fields.
+It is an error to call this method twice for a given request.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B send_info(status, headers)
+Send non\-final (informational) response to a client. \fIstatus\fP
+must be in the range [100, 199], inclusive. \fIheaders\fP is a
+hash containing response header fields. Its key must be a
+string, and the associated value must be either string or
+array of strings. Since this is not a final response, even if
+this method is invoked, request is still forwarded to a
+backend unless \fI\%Nghttpx::Response#return\fP is called.
+This method can be called multiple times. It cannot be called
+after \fI\%Nghttpx::Response#return\fP is called.
+.UNINDENT
+.UNINDENT
+.SS MRUBY EXAMPLES
+.sp
+Modify request path:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+class App
+ def on_req(env)
+ env.req.path = \(dq/apps#{env.req.path}\(dq
+ end
+end
+
+App.new
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Don\(aqt forget to instantiate and evaluate object at the last line.
+.sp
+Restrict permission of viewing a content to a specific client
+addresses:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+class App
+ def on_req(env)
+ allowed_clients = [\(dq127.0.0.1\(dq, \(dq::1\(dq]
+
+ if env.req.path.start_with?(\(dq/log/\(dq) &&
+ !allowed_clients.include?(env.remote_addr) then
+ env.resp.status = 404
+ env.resp.return \(dqpermission denied\(dq
+ end
+ end
+end
+
+App.new
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SH API ENDPOINTS
+.sp
+nghttpx exposes API endpoints to manipulate it via HTTP based API. By
+default, API endpoint is disabled. To enable it, add a dedicated
+frontend for API using \fI\%\-\-frontend\fP option with \(dqapi\(dq
+parameter. All requests which come from this frontend address, will
+be treated as API request.
+.sp
+The response is normally JSON dictionary, and at least includes the
+following keys:
+.INDENT 0.0
+.TP
+.B status
+The status of the request processing. The following values are
+defined:
+.INDENT 7.0
+.TP
+.B Success
+The request was successful.
+.TP
+.B Failure
+The request was failed. No change has been made.
+.UNINDENT
+.TP
+.B code
+HTTP status code
+.UNINDENT
+.sp
+Additionally, depending on the API endpoint, \fBdata\fP key may be
+present, and its value contains the API endpoint specific data.
+.sp
+We wrote \(dqnormally\(dq, since nghttpx may return ordinal HTML response in
+some cases where the error has occurred before reaching API endpoint
+(e.g., header field is too large).
+.sp
+The following section describes available API endpoints.
+.SS POST /api/v1beta1/backendconfig
+.sp
+This API replaces the current backend server settings with the
+requested ones. The request method should be POST, but PUT is also
+acceptable. The request body must be nghttpx configuration file
+format. For configuration file format, see \fI\%FILES\fP section. The
+line separator inside the request body must be single LF (0x0A).
+Currently, only \fI\%backend\fP option is parsed, the
+others are simply ignored. The semantics of this API is replace the
+current backend with the backend options in request body. Describe
+the desired set of backend severs, and nghttpx makes it happen. If
+there is no \fI\%backend\fP option is found in request
+body, the current set of backend is replaced with the \fI\%backend\fP option\(aqs default value, which is \fB127.0.0.1,80\fP\&.
+.sp
+The replacement is done instantly without breaking existing
+connections or requests. It also avoids any process creation as is
+the case with hot swapping with signals.
+.sp
+The one limitation is that only numeric IP address is allowed in
+\fI\%backend\fP in request body unless \(dqdns\(dq parameter
+is used while non numeric hostname is allowed in command\-line or
+configuration file is read using \fI\%\-\-conf\fP\&.
+.SS GET /api/v1beta1/configrevision
+.sp
+This API returns configuration revision of the current nghttpx. The
+configuration revision is opaque string, and it changes after each
+reloading by SIGHUP. With this API, an external application knows
+that whether nghttpx has finished reloading its configuration by
+comparing the configuration revisions between before and after
+reloading. It is recommended to disable persistent (keep\-alive)
+connection for this purpose in order to avoid to send a request using
+the reused connection which may bound to an old process.
+.sp
+This API returns response including \fBdata\fP key. Its value is JSON
+object, and it contains at least the following key:
+.INDENT 0.0
+.TP
+.B configRevision
+The configuration revision of the current nghttpx
+.UNINDENT
+.SH SEE ALSO
+.sp
+\fBnghttp(1)\fP, \fBnghttpd(1)\fP, \fBh2load(1)\fP
+.SH AUTHOR
+Tatsuhiro Tsujikawa
+.SH COPYRIGHT
+2012, 2015, 2016, Tatsuhiro Tsujikawa
+.\" Generated by docutils manpage writer.
+.
diff --git a/doc/nghttpx.1.rst b/doc/nghttpx.1.rst
new file mode 100644
index 0000000..03109e4
--- /dev/null
+++ b/doc/nghttpx.1.rst
@@ -0,0 +1,2526 @@
+
+.. GENERATED by help2rst.py. DO NOT EDIT DIRECTLY.
+
+.. program:: nghttpx
+
+nghttpx(1)
+==========
+
+SYNOPSIS
+--------
+
+**nghttpx** [OPTIONS]... [<PRIVATE_KEY> <CERT>]
+
+DESCRIPTION
+-----------
+
+A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.
+
+.. describe:: <PRIVATE_KEY>
+
+
+ Set path to server's private key. Required unless
+ "no-tls" parameter is used in :option:`--frontend` option.
+
+.. describe:: <CERT>
+
+ Set path to server's certificate. Required unless
+ "no-tls" parameter is used in :option:`--frontend` option. To
+ make OCSP stapling work, this must be an absolute path.
+
+
+OPTIONS
+-------
+
+The options are categorized into several groups.
+
+Connections
+~~~~~~~~~~~
+
+.. option:: -b, --backend=(<HOST>,<PORT>|unix:<PATH>)[;[<PATTERN>[:...]][[;<PARAM>]...]
+
+
+ Set backend host and port. The multiple backend
+ addresses are accepted by repeating this option. UNIX
+ domain socket can be specified by prefixing path name
+ with "unix:" (e.g., unix:/var/run/backend.sock).
+
+ Optionally, if <PATTERN>s are given, the backend address
+ is only used if request matches the pattern. The
+ pattern matching is closely designed to ServeMux in
+ net/http package of Go programming language. <PATTERN>
+ consists of path, host + path or just host. The path
+ must start with "*/*". If it ends with "*/*", it matches
+ all request path in its subtree. To deal with the
+ request to the directory without trailing slash, the
+ path which ends with "*/*" also matches the request path
+ which only lacks trailing '*/*' (e.g., path "*/foo/*"
+ matches request path "*/foo*"). If it does not end with
+ "*/*", it performs exact match against the request path.
+ If host is given, it performs a match against the
+ request host. For a request received on the frontend
+ listener with "sni-fwd" parameter enabled, SNI host is
+ used instead of a request host. If host alone is given,
+ "*/*" is appended to it, so that it matches all request
+ paths under the host (e.g., specifying "nghttp2.org"
+ equals to "nghttp2.org/"). CONNECT method is treated
+ specially. It does not have path, and we don't allow
+ empty path. To workaround this, we assume that CONNECT
+ method has "*/*" as path.
+
+ Patterns with host take precedence over patterns with
+ just path. Then, longer patterns take precedence over
+ shorter ones.
+
+ Host can include "\*" in the left most position to
+ indicate wildcard match (only suffix match is done).
+ The "\*" must match at least one character. For example,
+ host pattern "\*.nghttp2.org" matches against
+ "www.nghttp2.org" and "git.ngttp2.org", but does not
+ match against "nghttp2.org". The exact hosts match
+ takes precedence over the wildcard hosts match.
+
+ If path part ends with "\*", it is treated as wildcard
+ path. The wildcard path behaves differently from the
+ normal path. For normal path, match is made around the
+ boundary of path component separator,"*/*". On the other
+ hand, the wildcard path does not take into account the
+ path component separator. All paths which include the
+ wildcard path without last "\*" as prefix, and are
+ strictly longer than wildcard path without last "\*" are
+ matched. "\*" must match at least one character. For
+ example, the pattern "*/foo\**" matches "*/foo/*" and
+ "*/foobar*". But it does not match "*/foo*", or "*/fo*".
+
+ If <PATTERN> is omitted or empty string, "*/*" is used as
+ pattern, which matches all request paths (catch-all
+ pattern). The catch-all backend must be given.
+
+ When doing a match, nghttpx made some normalization to
+ pattern, request host and path. For host part, they are
+ converted to lower case. For path part, percent-encoded
+ unreserved characters defined in RFC 3986 are decoded,
+ and any dot-segments (".." and ".") are resolved and
+ removed.
+
+ For example, :option:`-b`\'127.0.0.1,8080;nghttp2.org/httpbin/'
+ matches the request host "nghttp2.org" and the request
+ path "*/httpbin/get*", but does not match the request host
+ "nghttp2.org" and the request path "*/index.html*".
+
+ The multiple <PATTERN>s can be specified, delimiting
+ them by ":". Specifying
+ :option:`-b`\'127.0.0.1,8080;nghttp2.org:www.nghttp2.org' has the
+ same effect to specify :option:`-b`\'127.0.0.1,8080;nghttp2.org'
+ and :option:`-b`\'127.0.0.1,8080;www.nghttp2.org'.
+
+ The backend addresses sharing same <PATTERN> are grouped
+ together forming load balancing group.
+
+ Several parameters <PARAM> are accepted after <PATTERN>.
+ The parameters are delimited by ";". The available
+ parameters are: "proto=<PROTO>", "tls",
+ "sni=<SNI_HOST>", "fall=<N>", "rise=<N>",
+ "affinity=<METHOD>", "dns", "redirect-if-not-tls",
+ "upgrade-scheme", "mruby=<PATH>",
+ "read-timeout=<DURATION>", "write-timeout=<DURATION>",
+ "group=<GROUP>", "group-weight=<N>", "weight=<N>", and
+ "dnf". The parameter consists of keyword, and
+ optionally followed by "=" and value. For example, the
+ parameter "proto=h2" consists of the keyword "proto" and
+ value "h2". The parameter "tls" consists of the keyword
+ "tls" without value. Each parameter is described as
+ follows.
+
+ The backend application protocol can be specified using
+ optional "proto" parameter, and in the form of
+ "proto=<PROTO>". <PROTO> should be one of the following
+ list without quotes: "h2", "http/1.1". The default
+ value of <PROTO> is "http/1.1". Note that usually "h2"
+ refers to HTTP/2 over TLS. But in this option, it may
+ mean HTTP/2 over cleartext TCP unless "tls" keyword is
+ used (see below).
+
+ TLS can be enabled by specifying optional "tls"
+ parameter. TLS is not enabled by default.
+
+ With "sni=<SNI_HOST>" parameter, it can override the TLS
+ SNI field value with given <SNI_HOST>. This will
+ default to the backend <HOST> name
+
+ The feature to detect whether backend is online or
+ offline can be enabled using optional "fall" and "rise"
+ parameters. Using "fall=<N>" parameter, if nghttpx
+ cannot connect to a this backend <N> times in a row,
+ this backend is assumed to be offline, and it is
+ excluded from load balancing. If <N> is 0, this backend
+ never be excluded from load balancing whatever times
+ nghttpx cannot connect to it, and this is the default.
+ There is also "rise=<N>" parameter. After backend was
+ excluded from load balancing group, nghttpx periodically
+ attempts to make a connection to the failed backend, and
+ if the connection is made successfully <N> times in a
+ row, the backend is assumed to be online, and it is now
+ eligible for load balancing target. If <N> is 0, a
+ backend is permanently offline, once it goes in that
+ state, and this is the default behaviour.
+
+ The session affinity is enabled using
+ "affinity=<METHOD>" parameter. If "ip" is given in
+ <METHOD>, client IP based session affinity is enabled.
+ If "cookie" is given in <METHOD>, cookie based session
+ affinity is enabled. If "none" is given in <METHOD>,
+ session affinity is disabled, and this is the default.
+ The session affinity is enabled per <PATTERN>. If at
+ least one backend has "affinity" parameter, and its
+ <METHOD> is not "none", session affinity is enabled for
+ all backend servers sharing the same <PATTERN>. It is
+ advised to set "affinity" parameter to all backend
+ explicitly if session affinity is desired. The session
+ affinity may break if one of the backend gets
+ unreachable, or backend settings are reloaded or
+ replaced by API.
+
+ If "affinity=cookie" is used, the additional
+ configuration is required.
+ "affinity-cookie-name=<NAME>" must be used to specify a
+ name of cookie to use. Optionally,
+ "affinity-cookie-path=<PATH>" can be used to specify a
+ path which cookie is applied. The optional
+ "affinity-cookie-secure=<SECURE>" controls the Secure
+ attribute of a cookie. The default value is "auto", and
+ the Secure attribute is determined by a request scheme.
+ If a request scheme is "https", then Secure attribute is
+ set. Otherwise, it is not set. If <SECURE> is "yes",
+ the Secure attribute is always set. If <SECURE> is
+ "no", the Secure attribute is always omitted.
+ "affinity-cookie-stickiness=<STICKINESS>" controls
+ stickiness of this affinity. If <STICKINESS> is
+ "loose", removing or adding a backend server might break
+ the affinity and the request might be forwarded to a
+ different backend server. If <STICKINESS> is "strict",
+ removing the designated backend server breaks affinity,
+ but adding new backend server does not cause breakage.
+ If the designated backend server becomes unavailable,
+ new backend server is chosen as if the request does not
+ have an affinity cookie. <STICKINESS> defaults to
+ "loose".
+
+ By default, name resolution of backend host name is done
+ at start up, or reloading configuration. If "dns"
+ parameter is given, name resolution takes place
+ dynamically. This is useful if backend address changes
+ frequently. If "dns" is given, name resolution of
+ backend host name at start up, or reloading
+ configuration is skipped.
+
+ If "redirect-if-not-tls" parameter is used, the matched
+ backend requires that frontend connection is TLS
+ encrypted. If it isn't, nghttpx responds to the request
+ with 308 status code, and https URI the client should
+ use instead is included in Location header field. The
+ port number in redirect URI is 443 by default, and can
+ be changed using :option:`--redirect-https-port` option. If at
+ least one backend has "redirect-if-not-tls" parameter,
+ this feature is enabled for all backend servers sharing
+ the same <PATTERN>. It is advised to set
+ "redirect-if-no-tls" parameter to all backends
+ explicitly if this feature is desired.
+
+ If "upgrade-scheme" parameter is used along with "tls"
+ parameter, HTTP/2 :scheme pseudo header field is changed
+ to "https" from "http" when forwarding a request to this
+ particular backend. This is a workaround for a backend
+ server which requires "https" :scheme pseudo header
+ field on TLS encrypted connection.
+
+ "mruby=<PATH>" parameter specifies a path to mruby
+ script file which is invoked when this pattern is
+ matched. All backends which share the same pattern must
+ have the same mruby path.
+
+ "read-timeout=<DURATION>" and "write-timeout=<DURATION>"
+ parameters specify the read and write timeout of the
+ backend connection when this pattern is matched. All
+ backends which share the same pattern must have the same
+ timeouts. If these timeouts are entirely omitted for a
+ pattern, :option:`--backend-read-timeout` and
+ :option:`--backend-write-timeout` are used.
+
+ "group=<GROUP>" parameter specifies the name of group
+ this backend address belongs to. By default, it belongs
+ to the unnamed default group. The name of group is
+ unique per pattern. "group-weight=<N>" parameter
+ specifies the weight of the group. The higher weight
+ gets more frequently selected by the load balancing
+ algorithm. <N> must be [1, 256] inclusive. The weight
+ 8 has 4 times more weight than 2. <N> must be the same
+ for all addresses which share the same <GROUP>. If
+ "group-weight" is omitted in an address, but the other
+ address which belongs to the same group specifies
+ "group-weight", its weight is used. If no
+ "group-weight" is specified for all addresses, the
+ weight of a group becomes 1. "group" and "group-weight"
+ are ignored if session affinity is enabled.
+
+ "weight=<N>" parameter specifies the weight of the
+ backend address inside a group which this address
+ belongs to. The higher weight gets more frequently
+ selected by the load balancing algorithm. <N> must be
+ [1, 256] inclusive. The weight 8 has 4 times more
+ weight than weight 2. If this parameter is omitted,
+ weight becomes 1. "weight" is ignored if session
+ affinity is enabled.
+
+ If "dnf" parameter is specified, an incoming request is
+ not forwarded to a backend and just consumed along with
+ the request body (actually a backend server never be
+ contacted). It is expected that the HTTP response is
+ generated by mruby script (see "mruby=<PATH>" parameter
+ above). "dnf" is an abbreviation of "do not forward".
+
+ Since ";" and ":" are used as delimiter, <PATTERN> must
+ not contain these characters. In order to include ":"
+ in <PATTERN>, one has to specify "%3A" (which is
+ percent-encoded from of ":") instead. Since ";" has
+ special meaning in shell, the option value must be
+ quoted.
+
+
+ Default: ``127.0.0.1,80``
+
+.. option:: -f, --frontend=(<HOST>,<PORT>|unix:<PATH>)[[;<PARAM>]...]
+
+ Set frontend host and port. If <HOST> is '\*', it
+ assumes all addresses including both IPv4 and IPv6.
+ UNIX domain socket can be specified by prefixing path
+ name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
+ This option can be used multiple times to listen to
+ multiple addresses.
+
+ This option can take 0 or more parameters, which are
+ described below. Note that "api" and "healthmon"
+ parameters are mutually exclusive.
+
+ Optionally, TLS can be disabled by specifying "no-tls"
+ parameter. TLS is enabled by default.
+
+ If "sni-fwd" parameter is used, when performing a match
+ to select a backend server, SNI host name received from
+ the client is used instead of the request host. See
+ :option:`--backend` option about the pattern match.
+
+ To make this frontend as API endpoint, specify "api"
+ parameter. This is disabled by default. It is
+ important to limit the access to the API frontend.
+ Otherwise, someone may change the backend server, and
+ break your services, or expose confidential information
+ to the outside the world.
+
+ To make this frontend as health monitor endpoint,
+ specify "healthmon" parameter. This is disabled by
+ default. Any requests which come through this address
+ are replied with 200 HTTP status, without no body.
+
+ To accept PROXY protocol version 1 and 2 on frontend
+ connection, specify "proxyproto" parameter. This is
+ disabled by default.
+
+ To receive HTTP/3 (QUIC) traffic, specify "quic"
+ parameter. It makes nghttpx listen on UDP port rather
+ than TCP port. UNIX domain socket, "api", and
+ "healthmon" parameters cannot be used with "quic"
+ parameter.
+
+
+ Default: ``*,3000``
+
+.. option:: --backlog=<N>
+
+ Set listen backlog size.
+
+ Default: ``65536``
+
+.. option:: --backend-address-family=(auto|IPv4|IPv6)
+
+ Specify address family of backend connections. If
+ "auto" is given, both IPv4 and IPv6 are considered. If
+ "IPv4" is given, only IPv4 address is considered. If
+ "IPv6" is given, only IPv6 address is considered.
+
+ Default: ``auto``
+
+.. option:: --backend-http-proxy-uri=<URI>
+
+ Specify proxy URI in the form
+ http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a proxy
+ requires authentication, specify <USER> and <PASS>.
+ Note that they must be properly percent-encoded. This
+ proxy is used when the backend connection is HTTP/2.
+ First, make a CONNECT request to the proxy and it
+ connects to the backend on behalf of nghttpx. This
+ forms tunnel. After that, nghttpx performs SSL/TLS
+ handshake with the downstream through the tunnel. The
+ timeouts when connecting and making CONNECT request can
+ be specified by :option:`--backend-read-timeout` and
+ :option:`--backend-write-timeout` options.
+
+
+Performance
+~~~~~~~~~~~
+
+.. option:: -n, --workers=<N>
+
+ Set the number of worker threads.
+
+ Default: ``1``
+
+.. option:: --single-thread
+
+ Run everything in one thread inside the worker process.
+ This feature is provided for better debugging
+ experience, or for the platforms which lack thread
+ support. If threading is disabled, this option is
+ always enabled.
+
+.. option:: --read-rate=<SIZE>
+
+ Set maximum average read rate on frontend connection.
+ Setting 0 to this option means read rate is unlimited.
+
+ Default: ``0``
+
+.. option:: --read-burst=<SIZE>
+
+ Set maximum read burst size on frontend connection.
+ Setting 0 to this option means read burst size is
+ unlimited.
+
+ Default: ``0``
+
+.. option:: --write-rate=<SIZE>
+
+ Set maximum average write rate on frontend connection.
+ Setting 0 to this option means write rate is unlimited.
+
+ Default: ``0``
+
+.. option:: --write-burst=<SIZE>
+
+ Set maximum write burst size on frontend connection.
+ Setting 0 to this option means write burst size is
+ unlimited.
+
+ Default: ``0``
+
+.. option:: --worker-read-rate=<SIZE>
+
+ Set maximum average read rate on frontend connection per
+ worker. Setting 0 to this option means read rate is
+ unlimited. Not implemented yet.
+
+ Default: ``0``
+
+.. option:: --worker-read-burst=<SIZE>
+
+ Set maximum read burst size on frontend connection per
+ worker. Setting 0 to this option means read burst size
+ is unlimited. Not implemented yet.
+
+ Default: ``0``
+
+.. option:: --worker-write-rate=<SIZE>
+
+ Set maximum average write rate on frontend connection
+ per worker. Setting 0 to this option means write rate
+ is unlimited. Not implemented yet.
+
+ Default: ``0``
+
+.. option:: --worker-write-burst=<SIZE>
+
+ Set maximum write burst size on frontend connection per
+ worker. Setting 0 to this option means write burst size
+ is unlimited. Not implemented yet.
+
+ Default: ``0``
+
+.. option:: --worker-frontend-connections=<N>
+
+ Set maximum number of simultaneous connections frontend
+ accepts. Setting 0 means unlimited.
+
+ Default: ``0``
+
+.. option:: --backend-connections-per-host=<N>
+
+ Set maximum number of backend concurrent connections
+ (and/or streams in case of HTTP/2) per origin host.
+ This option is meaningful when :option:`--http2-proxy` option is
+ used. The origin host is determined by authority
+ portion of request URI (or :authority header field for
+ HTTP/2). To limit the number of connections per
+ frontend for default mode, use
+ :option:`--backend-connections-per-frontend`\.
+
+ Default: ``8``
+
+.. option:: --backend-connections-per-frontend=<N>
+
+ Set maximum number of backend concurrent connections
+ (and/or streams in case of HTTP/2) per frontend. This
+ option is only used for default mode. 0 means
+ unlimited. To limit the number of connections per host
+ with :option:`--http2-proxy` option, use
+ :option:`--backend-connections-per-host`\.
+
+ Default: ``0``
+
+.. option:: --rlimit-nofile=<N>
+
+ Set maximum number of open files (RLIMIT_NOFILE) to <N>.
+ If 0 is given, nghttpx does not set the limit.
+
+ Default: ``0``
+
+.. option:: --rlimit-memlock=<N>
+
+ Set maximum number of bytes of memory that may be locked
+ into RAM. If 0 is given, nghttpx does not set the
+ limit.
+
+ Default: ``0``
+
+.. option:: --backend-request-buffer=<SIZE>
+
+ Set buffer size used to store backend request.
+
+ Default: ``16K``
+
+.. option:: --backend-response-buffer=<SIZE>
+
+ Set buffer size used to store backend response.
+
+ Default: ``128K``
+
+.. option:: --fastopen=<N>
+
+ Enables "TCP Fast Open" for the listening socket and
+ limits the maximum length for the queue of connections
+ that have not yet completed the three-way handshake. If
+ value is 0 then fast open is disabled.
+
+ Default: ``0``
+
+.. option:: --no-kqueue
+
+ Don't use kqueue. This option is only applicable for
+ the platforms which have kqueue. For other platforms,
+ this option will be simply ignored.
+
+
+Timeout
+~~~~~~~
+
+.. option:: --frontend-http2-read-timeout=<DURATION>
+
+ Specify read timeout for HTTP/2 frontend connection.
+
+ Default: ``3m``
+
+.. option:: --frontend-http3-read-timeout=<DURATION>
+
+ Specify read timeout for HTTP/3 frontend connection.
+
+ Default: ``3m``
+
+.. option:: --frontend-read-timeout=<DURATION>
+
+ Specify read timeout for HTTP/1.1 frontend connection.
+
+ Default: ``1m``
+
+.. option:: --frontend-write-timeout=<DURATION>
+
+ Specify write timeout for all frontend connections.
+
+ Default: ``30s``
+
+.. option:: --frontend-keep-alive-timeout=<DURATION>
+
+ Specify keep-alive timeout for frontend HTTP/1
+ connection.
+
+ Default: ``1m``
+
+.. option:: --stream-read-timeout=<DURATION>
+
+ Specify read timeout for HTTP/2 streams. 0 means no
+ timeout.
+
+ Default: ``0``
+
+.. option:: --stream-write-timeout=<DURATION>
+
+ Specify write timeout for HTTP/2 streams. 0 means no
+ timeout.
+
+ Default: ``1m``
+
+.. option:: --backend-read-timeout=<DURATION>
+
+ Specify read timeout for backend connection.
+
+ Default: ``1m``
+
+.. option:: --backend-write-timeout=<DURATION>
+
+ Specify write timeout for backend connection.
+
+ Default: ``30s``
+
+.. option:: --backend-connect-timeout=<DURATION>
+
+ Specify timeout before establishing TCP connection to
+ backend.
+
+ Default: ``30s``
+
+.. option:: --backend-keep-alive-timeout=<DURATION>
+
+ Specify keep-alive timeout for backend HTTP/1
+ connection.
+
+ Default: ``2s``
+
+.. option:: --listener-disable-timeout=<DURATION>
+
+ After accepting connection failed, connection listener
+ is disabled for a given amount of time. Specifying 0
+ disables this feature.
+
+ Default: ``30s``
+
+.. option:: --frontend-http2-setting-timeout=<DURATION>
+
+ Specify timeout before SETTINGS ACK is received from
+ client.
+
+ Default: ``10s``
+
+.. option:: --backend-http2-settings-timeout=<DURATION>
+
+ Specify timeout before SETTINGS ACK is received from
+ backend server.
+
+ Default: ``10s``
+
+.. option:: --backend-max-backoff=<DURATION>
+
+ Specify maximum backoff interval. This is used when
+ doing health check against offline backend (see "fail"
+ parameter in :option:`--backend` option). It is also used to
+ limit the maximum interval to temporarily disable
+ backend when nghttpx failed to connect to it. These
+ intervals are calculated using exponential backoff, and
+ consecutive failed attempts increase the interval. This
+ option caps its maximum value.
+
+ Default: ``2m``
+
+
+SSL/TLS
+~~~~~~~
+
+.. option:: --ciphers=<SUITE>
+
+ Set allowed cipher list for frontend connection. The
+ format of the string is described in OpenSSL ciphers(1).
+ This option sets cipher suites for TLSv1.2 or earlier.
+ Use :option:`--tls13-ciphers` for TLSv1.3.
+
+ Default: ``ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384``
+
+.. option:: --tls13-ciphers=<SUITE>
+
+ Set allowed cipher list for frontend connection. The
+ format of the string is described in OpenSSL ciphers(1).
+ This option sets cipher suites for TLSv1.3. Use
+ :option:`--ciphers` for TLSv1.2 or earlier.
+
+ Default: ``TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256``
+
+.. option:: --client-ciphers=<SUITE>
+
+ Set allowed cipher list for backend connection. The
+ format of the string is described in OpenSSL ciphers(1).
+ This option sets cipher suites for TLSv1.2 or earlier.
+ Use :option:`--tls13-client-ciphers` for TLSv1.3.
+
+ Default: ``ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384``
+
+.. option:: --tls13-client-ciphers=<SUITE>
+
+ Set allowed cipher list for backend connection. The
+ format of the string is described in OpenSSL ciphers(1).
+ This option sets cipher suites for TLSv1.3. Use
+ :option:`--tls13-client-ciphers` for TLSv1.2 or earlier.
+
+ Default: ``TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256``
+
+.. option:: --ecdh-curves=<LIST>
+
+ Set supported curve list for frontend connections.
+ <LIST> is a colon separated list of curve NID or names
+ in the preference order. The supported curves depend on
+ the linked OpenSSL library. This function requires
+ OpenSSL >= 1.0.2.
+
+ Default: ``X25519:P-256:P-384:P-521``
+
+.. option:: -k, --insecure
+
+ Don't verify backend server's certificate if TLS is
+ enabled for backend connections.
+
+.. option:: --cacert=<PATH>
+
+ Set path to trusted CA certificate file. It is used in
+ backend TLS connections to verify peer's certificate.
+ It is also used to verify OCSP response from the script
+ set by :option:`--fetch-ocsp-response-file`\. The file must be in
+ PEM format. It can contain multiple certificates. If
+ the linked OpenSSL is configured to load system wide
+ certificates, they are loaded at startup regardless of
+ this option.
+
+.. option:: --private-key-passwd-file=<PATH>
+
+ Path to file that contains password for the server's
+ private key. If none is given and the private key is
+ password protected it'll be requested interactively.
+
+.. option:: --subcert=<KEYPATH>:<CERTPATH>[[;<PARAM>]...]
+
+ Specify additional certificate and private key file.
+ nghttpx will choose certificates based on the hostname
+ indicated by client using TLS SNI extension. If nghttpx
+ is built with OpenSSL >= 1.0.2, the shared elliptic
+ curves (e.g., P-256) between client and server are also
+ taken into consideration. This allows nghttpx to send
+ ECDSA certificate to modern clients, while sending RSA
+ based certificate to older clients. This option can be
+ used multiple times. To make OCSP stapling work,
+ <CERTPATH> must be absolute path.
+
+ Additional parameter can be specified in <PARAM>. The
+ available <PARAM> is "sct-dir=<DIR>".
+
+ "sct-dir=<DIR>" specifies the path to directory which
+ contains \*.sct files for TLS
+ signed_certificate_timestamp extension (RFC 6962). This
+ feature requires OpenSSL >= 1.0.2. See also
+ :option:`--tls-sct-dir` option.
+
+.. option:: --dh-param-file=<PATH>
+
+ Path to file that contains DH parameters in PEM format.
+ Without this option, DHE cipher suites are not
+ available.
+
+.. option:: --alpn-list=<LIST>
+
+ Comma delimited list of ALPN protocol identifier sorted
+ in the order of preference. That means most desirable
+ protocol comes first. The parameter must be delimited
+ by a single comma only and any white spaces are treated
+ as a part of protocol string.
+
+ Default: ``h2,h2-16,h2-14,http/1.1``
+
+.. option:: --verify-client
+
+ Require and verify client certificate.
+
+.. option:: --verify-client-cacert=<PATH>
+
+ Path to file that contains CA certificates to verify
+ client certificate. The file must be in PEM format. It
+ can contain multiple certificates.
+
+.. option:: --verify-client-tolerate-expired
+
+ Accept expired client certificate. Operator should
+ handle the expired client certificate by some means
+ (e.g., mruby script). Otherwise, this option might
+ cause a security risk.
+
+.. option:: --client-private-key-file=<PATH>
+
+ Path to file that contains client private key used in
+ backend client authentication.
+
+.. option:: --client-cert-file=<PATH>
+
+ Path to file that contains client certificate used in
+ backend client authentication.
+
+.. option:: --tls-min-proto-version=<VER>
+
+ Specify minimum SSL/TLS protocol. The name matching is
+ done in case-insensitive manner. The versions between
+ :option:`--tls-min-proto-version` and :option:`\--tls-max-proto-version` are
+ enabled. If the protocol list advertised by client does
+ not overlap this range, you will receive the error
+ message "unknown protocol". If a protocol version lower
+ than TLSv1.2 is specified, make sure that the compatible
+ ciphers are included in :option:`--ciphers` option. The default
+ cipher list only includes ciphers compatible with
+ TLSv1.2 or above. The available versions are:
+ TLSv1.3, TLSv1.2, TLSv1.1, and TLSv1.0
+
+ Default: ``TLSv1.2``
+
+.. option:: --tls-max-proto-version=<VER>
+
+ Specify maximum SSL/TLS protocol. The name matching is
+ done in case-insensitive manner. The versions between
+ :option:`--tls-min-proto-version` and :option:`\--tls-max-proto-version` are
+ enabled. If the protocol list advertised by client does
+ not overlap this range, you will receive the error
+ message "unknown protocol". The available versions are:
+ TLSv1.3, TLSv1.2, TLSv1.1, and TLSv1.0
+
+ Default: ``TLSv1.3``
+
+.. option:: --tls-ticket-key-file=<PATH>
+
+ Path to file that contains random data to construct TLS
+ session ticket parameters. If aes-128-cbc is given in
+ :option:`--tls-ticket-key-cipher`\, the file must contain exactly
+ 48 bytes. If aes-256-cbc is given in
+ :option:`--tls-ticket-key-cipher`\, the file must contain exactly
+ 80 bytes. This options can be used repeatedly to
+ specify multiple ticket parameters. If several files
+ are given, only the first key is used to encrypt TLS
+ session tickets. Other keys are accepted but server
+ will issue new session ticket with first key. This
+ allows session key rotation. Please note that key
+ rotation does not occur automatically. User should
+ rearrange files or change options values and restart
+ nghttpx gracefully. If opening or reading given file
+ fails, all loaded keys are discarded and it is treated
+ as if none of this option is given. If this option is
+ not given or an error occurred while opening or reading
+ a file, key is generated every 1 hour internally and
+ they are valid for 12 hours. This is recommended if
+ ticket key sharing between nghttpx instances is not
+ required.
+
+.. option:: --tls-ticket-key-memcached=<HOST>,<PORT>[;tls]
+
+ Specify address of memcached server to get TLS ticket
+ keys for session resumption. This enables shared TLS
+ ticket key between multiple nghttpx instances. nghttpx
+ does not set TLS ticket key to memcached. The external
+ ticket key generator is required. nghttpx just gets TLS
+ ticket keys from memcached, and use them, possibly
+ replacing current set of keys. It is up to extern TLS
+ ticket key generator to rotate keys frequently. See
+ "TLS SESSION TICKET RESUMPTION" section in manual page
+ to know the data format in memcached entry. Optionally,
+ memcached connection can be encrypted with TLS by
+ specifying "tls" parameter.
+
+.. option:: --tls-ticket-key-memcached-address-family=(auto|IPv4|IPv6)
+
+ Specify address family of memcached connections to get
+ TLS ticket keys. If "auto" is given, both IPv4 and IPv6
+ are considered. If "IPv4" is given, only IPv4 address
+ is considered. If "IPv6" is given, only IPv6 address is
+ considered.
+
+ Default: ``auto``
+
+.. option:: --tls-ticket-key-memcached-interval=<DURATION>
+
+ Set interval to get TLS ticket keys from memcached.
+
+ Default: ``10m``
+
+.. option:: --tls-ticket-key-memcached-max-retry=<N>
+
+ Set maximum number of consecutive retries before
+ abandoning TLS ticket key retrieval. If this number is
+ reached, the attempt is considered as failure, and
+ "failure" count is incremented by 1, which contributed
+ to the value controlled
+ :option:`--tls-ticket-key-memcached-max-fail` option.
+
+ Default: ``3``
+
+.. option:: --tls-ticket-key-memcached-max-fail=<N>
+
+ Set maximum number of consecutive failure before
+ disabling TLS ticket until next scheduled key retrieval.
+
+ Default: ``2``
+
+.. option:: --tls-ticket-key-cipher=<CIPHER>
+
+ Specify cipher to encrypt TLS session ticket. Specify
+ either aes-128-cbc or aes-256-cbc. By default,
+ aes-128-cbc is used.
+
+.. option:: --tls-ticket-key-memcached-cert-file=<PATH>
+
+ Path to client certificate for memcached connections to
+ get TLS ticket keys.
+
+.. option:: --tls-ticket-key-memcached-private-key-file=<PATH>
+
+ Path to client private key for memcached connections to
+ get TLS ticket keys.
+
+.. option:: --fetch-ocsp-response-file=<PATH>
+
+ Path to fetch-ocsp-response script file. It should be
+ absolute path.
+
+ Default: ``/usr/local/share/nghttp2/fetch-ocsp-response``
+
+.. option:: --ocsp-update-interval=<DURATION>
+
+ Set interval to update OCSP response cache.
+
+ Default: ``4h``
+
+.. option:: --ocsp-startup
+
+ Start accepting connections after initial attempts to
+ get OCSP responses finish. It does not matter some of
+ the attempts fail. This feature is useful if OCSP
+ responses must be available before accepting
+ connections.
+
+.. option:: --no-verify-ocsp
+
+ nghttpx does not verify OCSP response.
+
+.. option:: --no-ocsp
+
+ Disable OCSP stapling.
+
+.. option:: --tls-session-cache-memcached=<HOST>,<PORT>[;tls]
+
+ Specify address of memcached server to store session
+ cache. This enables shared session cache between
+ multiple nghttpx instances. Optionally, memcached
+ connection can be encrypted with TLS by specifying "tls"
+ parameter.
+
+.. option:: --tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
+
+ Specify address family of memcached connections to store
+ session cache. If "auto" is given, both IPv4 and IPv6
+ are considered. If "IPv4" is given, only IPv4 address
+ is considered. If "IPv6" is given, only IPv6 address is
+ considered.
+
+ Default: ``auto``
+
+.. option:: --tls-session-cache-memcached-cert-file=<PATH>
+
+ Path to client certificate for memcached connections to
+ store session cache.
+
+.. option:: --tls-session-cache-memcached-private-key-file=<PATH>
+
+ Path to client private key for memcached connections to
+ store session cache.
+
+.. option:: --tls-dyn-rec-warmup-threshold=<SIZE>
+
+ Specify the threshold size for TLS dynamic record size
+ behaviour. During a TLS session, after the threshold
+ number of bytes have been written, the TLS record size
+ will be increased to the maximum allowed (16K). The max
+ record size will continue to be used on the active TLS
+ session. After :option:`--tls-dyn-rec-idle-timeout` has elapsed,
+ the record size is reduced to 1300 bytes. Specify 0 to
+ always use the maximum record size, regardless of idle
+ period. This behaviour applies to all TLS based
+ frontends, and TLS HTTP/2 backends.
+
+ Default: ``1M``
+
+.. option:: --tls-dyn-rec-idle-timeout=<DURATION>
+
+ Specify TLS dynamic record size behaviour timeout. See
+ :option:`--tls-dyn-rec-warmup-threshold` for more information.
+ This behaviour applies to all TLS based frontends, and
+ TLS HTTP/2 backends.
+
+ Default: ``1s``
+
+.. option:: --no-http2-cipher-block-list
+
+ Allow block listed cipher suite on frontend HTTP/2
+ connection. See
+ https://tools.ietf.org/html/rfc7540#appendix-A for the
+ complete HTTP/2 cipher suites block list.
+
+.. option:: --client-no-http2-cipher-block-list
+
+ Allow block listed cipher suite on backend HTTP/2
+ connection. See
+ https://tools.ietf.org/html/rfc7540#appendix-A for the
+ complete HTTP/2 cipher suites block list.
+
+.. option:: --tls-sct-dir=<DIR>
+
+ Specifies the directory where \*.sct files exist. All
+ \*.sct files in <DIR> are read, and sent as
+ extension_data of TLS signed_certificate_timestamp (RFC
+ 6962) to client. These \*.sct files are for the
+ certificate specified in positional command-line
+ argument <CERT>, or certificate option in configuration
+ file. For additional certificates, use :option:`--subcert`
+ option. This option requires OpenSSL >= 1.0.2.
+
+.. option:: --psk-secrets=<PATH>
+
+ Read list of PSK identity and secrets from <PATH>. This
+ is used for frontend connection. The each line of input
+ file is formatted as <identity>:<hex-secret>, where
+ <identity> is PSK identity, and <hex-secret> is secret
+ in hex. An empty line, and line which starts with '#'
+ are skipped. The default enabled cipher list might not
+ contain any PSK cipher suite. In that case, desired PSK
+ cipher suites must be enabled using :option:`--ciphers` option.
+ The desired PSK cipher suite may be block listed by
+ HTTP/2. To use those cipher suites with HTTP/2,
+ consider to use :option:`--no-http2-cipher-block-list` option.
+ But be aware its implications.
+
+.. option:: --client-psk-secrets=<PATH>
+
+ Read PSK identity and secrets from <PATH>. This is used
+ for backend connection. The each line of input file is
+ formatted as <identity>:<hex-secret>, where <identity>
+ is PSK identity, and <hex-secret> is secret in hex. An
+ empty line, and line which starts with '#' are skipped.
+ The first identity and secret pair encountered is used.
+ The default enabled cipher list might not contain any
+ PSK cipher suite. In that case, desired PSK cipher
+ suites must be enabled using :option:`--client-ciphers` option.
+ The desired PSK cipher suite may be block listed by
+ HTTP/2. To use those cipher suites with HTTP/2,
+ consider to use :option:`--client-no-http2-cipher-block-list`
+ option. But be aware its implications.
+
+.. option:: --tls-no-postpone-early-data
+
+ By default, except for QUIC connections, nghttpx
+ postpones forwarding HTTP requests sent in early data,
+ including those sent in partially in it, until TLS
+ handshake finishes. If all backend server recognizes
+ "Early-Data" header field, using this option makes
+ nghttpx not postpone forwarding request and get full
+ potential of 0-RTT data.
+
+.. option:: --tls-max-early-data=<SIZE>
+
+ Sets the maximum amount of 0-RTT data that server
+ accepts.
+
+ Default: ``16K``
+
+.. option:: --tls-ktls
+
+ Enable ktls. For server, ktls is enable if
+ :option:`--tls-session-cache-memcached` is not configured.
+
+
+HTTP/2
+~~~~~~
+
+.. option:: -c, --frontend-http2-max-concurrent-streams=<N>
+
+ Set the maximum number of the concurrent streams in one
+ frontend HTTP/2 session.
+
+ Default: ``100``
+
+.. option:: --backend-http2-max-concurrent-streams=<N>
+
+ Set the maximum number of the concurrent streams in one
+ backend HTTP/2 session. This sets maximum number of
+ concurrent opened pushed streams. The maximum number of
+ concurrent requests are set by a remote server.
+
+ Default: ``100``
+
+.. option:: --frontend-http2-window-size=<SIZE>
+
+ Sets the per-stream initial window size of HTTP/2
+ frontend connection.
+
+ Default: ``65535``
+
+.. option:: --frontend-http2-connection-window-size=<SIZE>
+
+ Sets the per-connection window size of HTTP/2 frontend
+ connection.
+
+ Default: ``65535``
+
+.. option:: --backend-http2-window-size=<SIZE>
+
+ Sets the initial window size of HTTP/2 backend
+ connection.
+
+ Default: ``65535``
+
+.. option:: --backend-http2-connection-window-size=<SIZE>
+
+ Sets the per-connection window size of HTTP/2 backend
+ connection.
+
+ Default: ``2147483647``
+
+.. option:: --http2-no-cookie-crumbling
+
+ Don't crumble cookie header field.
+
+.. option:: --padding=<N>
+
+ Add at most <N> bytes to a HTTP/2 frame payload as
+ padding. Specify 0 to disable padding. This option is
+ meant for debugging purpose and not intended to enhance
+ protocol security.
+
+.. option:: --no-server-push
+
+ Disable HTTP/2 server push. Server push is supported by
+ default mode and HTTP/2 frontend via Link header field.
+ It is also supported if both frontend and backend are
+ HTTP/2 in default mode. In this case, server push from
+ backend session is relayed to frontend, and server push
+ via Link header field is also supported.
+
+.. option:: --frontend-http2-optimize-write-buffer-size
+
+ (Experimental) Enable write buffer size optimization in
+ frontend HTTP/2 TLS connection. This optimization aims
+ to reduce write buffer size so that it only contains
+ bytes which can send immediately. This makes server
+ more responsive to prioritized HTTP/2 stream because the
+ buffering of lower priority stream is reduced. This
+ option is only effective on recent Linux platform.
+
+.. option:: --frontend-http2-optimize-window-size
+
+ (Experimental) Automatically tune connection level
+ window size of frontend HTTP/2 TLS connection. If this
+ feature is enabled, connection window size starts with
+ the default window size, 65535 bytes. nghttpx
+ automatically adjusts connection window size based on
+ TCP receiving window size. The maximum window size is
+ capped by the value specified by
+ :option:`--frontend-http2-connection-window-size`\. Since the
+ stream is subject to stream level window size, it should
+ be adjusted using :option:`--frontend-http2-window-size` option as
+ well. This option is only effective on recent Linux
+ platform.
+
+.. option:: --frontend-http2-encoder-dynamic-table-size=<SIZE>
+
+ Specify the maximum dynamic table size of HPACK encoder
+ in the frontend HTTP/2 connection. The decoder (client)
+ specifies the maximum dynamic table size it accepts.
+ Then the negotiated dynamic table size is the minimum of
+ this option value and the value which client specified.
+
+ Default: ``4K``
+
+.. option:: --frontend-http2-decoder-dynamic-table-size=<SIZE>
+
+ Specify the maximum dynamic table size of HPACK decoder
+ in the frontend HTTP/2 connection.
+
+ Default: ``4K``
+
+.. option:: --backend-http2-encoder-dynamic-table-size=<SIZE>
+
+ Specify the maximum dynamic table size of HPACK encoder
+ in the backend HTTP/2 connection. The decoder (backend)
+ specifies the maximum dynamic table size it accepts.
+ Then the negotiated dynamic table size is the minimum of
+ this option value and the value which backend specified.
+
+ Default: ``4K``
+
+.. option:: --backend-http2-decoder-dynamic-table-size=<SIZE>
+
+ Specify the maximum dynamic table size of HPACK decoder
+ in the backend HTTP/2 connection.
+
+ Default: ``4K``
+
+
+Mode
+~~~~
+
+.. describe:: (default mode)
+
+
+ Accept HTTP/2, and HTTP/1.1 over SSL/TLS. "no-tls"
+ parameter is used in :option:`--frontend` option, accept HTTP/2
+ and HTTP/1.1 over cleartext TCP. The incoming HTTP/1.1
+ connection can be upgraded to HTTP/2 through HTTP
+ Upgrade.
+
+.. option:: -s, --http2-proxy
+
+ Like default mode, but enable forward proxy. This is so
+ called HTTP/2 proxy mode.
+
+
+Logging
+~~~~~~~
+
+.. option:: -L, --log-level=<LEVEL>
+
+ Set the severity level of log output. <LEVEL> must be
+ one of INFO, NOTICE, WARN, ERROR and FATAL.
+
+ Default: ``NOTICE``
+
+.. option:: --accesslog-file=<PATH>
+
+ Set path to write access log. To reopen file, send USR1
+ signal to nghttpx.
+
+.. option:: --accesslog-syslog
+
+ Send access log to syslog. If this option is used,
+ :option:`--accesslog-file` option is ignored.
+
+.. option:: --accesslog-format=<FORMAT>
+
+ Specify format string for access log. The default
+ format is combined format. The following variables are
+ available:
+
+ * $remote_addr: client IP address.
+ * $time_local: local time in Common Log format.
+ * $time_iso8601: local time in ISO 8601 format.
+ * $request: HTTP request line.
+ * $status: HTTP response status code.
+ * $body_bytes_sent: the number of bytes sent to client
+ as response body.
+ * $http_<VAR>: value of HTTP request header <VAR> where
+ '_' in <VAR> is replaced with '-'.
+ * $remote_port: client port.
+ * $server_port: server port.
+ * $request_time: request processing time in seconds with
+ milliseconds resolution.
+ * $pid: PID of the running process.
+ * $alpn: ALPN identifier of the protocol which generates
+ the response. For HTTP/1, ALPN is always http/1.1,
+ regardless of minor version.
+ * $tls_cipher: cipher used for SSL/TLS connection.
+ * $tls_client_fingerprint_sha256: SHA-256 fingerprint of
+ client certificate.
+ * $tls_client_fingerprint_sha1: SHA-1 fingerprint of
+ client certificate.
+ * $tls_client_subject_name: subject name in client
+ certificate.
+ * $tls_client_issuer_name: issuer name in client
+ certificate.
+ * $tls_client_serial: serial number in client
+ certificate.
+ * $tls_protocol: protocol for SSL/TLS connection.
+ * $tls_session_id: session ID for SSL/TLS connection.
+ * $tls_session_reused: "r" if SSL/TLS session was
+ reused. Otherwise, "."
+ * $tls_sni: SNI server name for SSL/TLS connection.
+ * $backend_host: backend host used to fulfill the
+ request. "-" if backend host is not available.
+ * $backend_port: backend port used to fulfill the
+ request. "-" if backend host is not available.
+ * $method: HTTP method
+ * $path: Request path including query. For CONNECT
+ request, authority is recorded.
+ * $path_without_query: $path up to the first '?'
+ character. For CONNECT request, authority is
+ recorded.
+ * $protocol_version: HTTP version (e.g., HTTP/1.1,
+ HTTP/2)
+
+ The variable can be enclosed by "{" and "}" for
+ disambiguation (e.g., ${remote_addr}).
+
+
+ Default: ``$remote_addr - - [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"``
+
+.. option:: --accesslog-write-early
+
+ Write access log when response header fields are
+ received from backend rather than when request
+ transaction finishes.
+
+.. option:: --errorlog-file=<PATH>
+
+ Set path to write error log. To reopen file, send USR1
+ signal to nghttpx. stderr will be redirected to the
+ error log file unless :option:`--errorlog-syslog` is used.
+
+ Default: ``/dev/stderr``
+
+.. option:: --errorlog-syslog
+
+ Send error log to syslog. If this option is used,
+ :option:`--errorlog-file` option is ignored.
+
+.. option:: --syslog-facility=<FACILITY>
+
+ Set syslog facility to <FACILITY>.
+
+ Default: ``daemon``
+
+
+HTTP
+~~~~
+
+.. option:: --add-x-forwarded-for
+
+ Append X-Forwarded-For header field to the downstream
+ request.
+
+.. option:: --strip-incoming-x-forwarded-for
+
+ Strip X-Forwarded-For header field from inbound client
+ requests.
+
+.. option:: --no-add-x-forwarded-proto
+
+ Don't append additional X-Forwarded-Proto header field
+ to the backend request. If inbound client sets
+ X-Forwarded-Proto, and
+ :option:`--no-strip-incoming-x-forwarded-proto` option is used,
+ they are passed to the backend.
+
+.. option:: --no-strip-incoming-x-forwarded-proto
+
+ Don't strip X-Forwarded-Proto header field from inbound
+ client requests.
+
+.. option:: --add-forwarded=<LIST>
+
+ Append RFC 7239 Forwarded header field with parameters
+ specified in comma delimited list <LIST>. The supported
+ parameters are "by", "for", "host", and "proto". By
+ default, the value of "by" and "for" parameters are
+ obfuscated string. See :option:`--forwarded-by` and
+ :option:`--forwarded-for` options respectively. Note that nghttpx
+ does not translate non-standard X-Forwarded-\* header
+ fields into Forwarded header field, and vice versa.
+
+.. option:: --strip-incoming-forwarded
+
+ Strip Forwarded header field from inbound client
+ requests.
+
+.. option:: --forwarded-by=(obfuscated|ip|<VALUE>)
+
+ Specify the parameter value sent out with "by" parameter
+ of Forwarded header field. If "obfuscated" is given,
+ the string is randomly generated at startup. If "ip" is
+ given, the interface address of the connection,
+ including port number, is sent with "by" parameter. In
+ case of UNIX domain socket, "localhost" is used instead
+ of address and port. User can also specify the static
+ obfuscated string. The limitation is that it must start
+ with "_", and only consists of character set
+ [A-Za-z0-9._-], as described in RFC 7239.
+
+ Default: ``obfuscated``
+
+.. option:: --forwarded-for=(obfuscated|ip)
+
+ Specify the parameter value sent out with "for"
+ parameter of Forwarded header field. If "obfuscated" is
+ given, the string is randomly generated for each client
+ connection. If "ip" is given, the remote client address
+ of the connection, without port number, is sent with
+ "for" parameter. In case of UNIX domain socket,
+ "localhost" is used instead of address.
+
+ Default: ``obfuscated``
+
+.. option:: --no-via
+
+ Don't append to Via header field. If Via header field
+ is received, it is left unaltered.
+
+.. option:: --no-strip-incoming-early-data
+
+ Don't strip Early-Data header field from inbound client
+ requests.
+
+.. option:: --no-location-rewrite
+
+ Don't rewrite location header field in default mode.
+ When :option:`--http2-proxy` is used, location header field will
+ not be altered regardless of this option.
+
+.. option:: --host-rewrite
+
+ Rewrite host and :authority header fields in default
+ mode. When :option:`--http2-proxy` is used, these headers will
+ not be altered regardless of this option.
+
+.. option:: --altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
+
+ Specify protocol ID, port, host and origin of
+ alternative service. <HOST>, <ORIGIN> and <PARAMS> are
+ optional. Empty <HOST> and <ORIGIN> are allowed and
+ they are treated as nothing is specified. They are
+ advertised in alt-svc header field only in HTTP/1.1
+ frontend. This option can be used multiple times to
+ specify multiple alternative services.
+ Example: :option:`--altsvc`\="h2,443,,,ma=3600; persist=1"
+
+.. option:: --http2-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
+
+ Just like :option:`--altsvc` option, but this altsvc is only sent
+ in HTTP/2 frontend.
+
+.. option:: --add-request-header=<HEADER>
+
+ Specify additional header field to add to request header
+ set. The field name must be lowercase. This option
+ just appends header field and won't replace anything
+ already set. This option can be used several times to
+ specify multiple header fields.
+ Example: :option:`--add-request-header`\="foo: bar"
+
+.. option:: --add-response-header=<HEADER>
+
+ Specify additional header field to add to response
+ header set. The field name must be lowercase. This
+ option just appends header field and won't replace
+ anything already set. This option can be used several
+ times to specify multiple header fields.
+ Example: :option:`--add-response-header`\="foo: bar"
+
+.. option:: --request-header-field-buffer=<SIZE>
+
+ Set maximum buffer size for incoming HTTP request header
+ field list. This is the sum of header name and value in
+ bytes. If trailer fields exist, they are counted
+ towards this number.
+
+ Default: ``64K``
+
+.. option:: --max-request-header-fields=<N>
+
+ Set maximum number of incoming HTTP request header
+ fields. If trailer fields exist, they are counted
+ towards this number.
+
+ Default: ``100``
+
+.. option:: --response-header-field-buffer=<SIZE>
+
+ Set maximum buffer size for incoming HTTP response
+ header field list. This is the sum of header name and
+ value in bytes. If trailer fields exist, they are
+ counted towards this number.
+
+ Default: ``64K``
+
+.. option:: --max-response-header-fields=<N>
+
+ Set maximum number of incoming HTTP response header
+ fields. If trailer fields exist, they are counted
+ towards this number.
+
+ Default: ``500``
+
+.. option:: --error-page=(<CODE>|*)=<PATH>
+
+ Set file path to custom error page served when nghttpx
+ originally generates HTTP error status code <CODE>.
+ <CODE> must be greater than or equal to 400, and at most
+ 599. If "\*" is used instead of <CODE>, it matches all
+ HTTP status code. If error status code comes from
+ backend server, the custom error pages are not used.
+
+.. option:: --server-name=<NAME>
+
+ Change server response header field value to <NAME>.
+
+ Default: ``nghttpx``
+
+.. option:: --no-server-rewrite
+
+ Don't rewrite server header field in default mode. When
+ :option:`--http2-proxy` is used, these headers will not be altered
+ regardless of this option.
+
+.. option:: --redirect-https-port=<PORT>
+
+ Specify the port number which appears in Location header
+ field when redirect to HTTPS URI is made due to
+ "redirect-if-not-tls" parameter in :option:`--backend` option.
+
+ Default: ``443``
+
+.. option:: --require-http-scheme
+
+ Always require http or https scheme in HTTP request. It
+ also requires that https scheme must be used for an
+ encrypted connection. Otherwise, http scheme must be
+ used. This option is recommended for a server
+ deployment which directly faces clients and the services
+ it provides only require http or https scheme.
+
+
+API
+~~~
+
+.. option:: --api-max-request-body=<SIZE>
+
+ Set the maximum size of request body for API request.
+
+ Default: ``32M``
+
+
+DNS
+~~~
+
+.. option:: --dns-cache-timeout=<DURATION>
+
+ Set duration that cached DNS results remain valid. Note
+ that nghttpx caches the unsuccessful results as well.
+
+ Default: ``10s``
+
+.. option:: --dns-lookup-timeout=<DURATION>
+
+ Set timeout that DNS server is given to respond to the
+ initial DNS query. For the 2nd and later queries,
+ server is given time based on this timeout, and it is
+ scaled linearly.
+
+ Default: ``5s``
+
+.. option:: --dns-max-try=<N>
+
+ Set the number of DNS query before nghttpx gives up name
+ lookup.
+
+ Default: ``2``
+
+.. option:: --frontend-max-requests=<N>
+
+ The number of requests that single frontend connection
+ can process. For HTTP/2, this is the number of streams
+ in one HTTP/2 connection. For HTTP/1, this is the
+ number of keep alive requests. This is hint to nghttpx,
+ and it may allow additional few requests. The default
+ value is unlimited.
+
+
+Debug
+~~~~~
+
+.. option:: --frontend-http2-dump-request-header=<PATH>
+
+ Dumps request headers received by HTTP/2 frontend to the
+ file denoted in <PATH>. The output is done in HTTP/1
+ header field format and each header block is followed by
+ an empty line. This option is not thread safe and MUST
+ NOT be used with option :option:`-n`\<N>, where <N> >= 2.
+
+.. option:: --frontend-http2-dump-response-header=<PATH>
+
+ Dumps response headers sent from HTTP/2 frontend to the
+ file denoted in <PATH>. The output is done in HTTP/1
+ header field format and each header block is followed by
+ an empty line. This option is not thread safe and MUST
+ NOT be used with option :option:`-n`\<N>, where <N> >= 2.
+
+.. option:: -o, --frontend-frame-debug
+
+ Print HTTP/2 frames in frontend to stderr. This option
+ is not thread safe and MUST NOT be used with option
+ :option:`-n`\=N, where N >= 2.
+
+
+Process
+~~~~~~~
+
+.. option:: -D, --daemon
+
+ Run in a background. If :option:`-D` is used, the current working
+ directory is changed to '*/*'.
+
+.. option:: --pid-file=<PATH>
+
+ Set path to save PID of this program.
+
+.. option:: --user=<USER>
+
+ Run this program as <USER>. This option is intended to
+ be used to drop root privileges.
+
+.. option:: --single-process
+
+ Run this program in a single process mode for debugging
+ purpose. Without this option, nghttpx creates at least
+ 2 processes: main and worker processes. If this option
+ is used, main and worker are unified into a single
+ process. nghttpx still spawns additional process if
+ neverbleed is used. In the single process mode, the
+ signal handling feature is disabled.
+
+.. option:: --max-worker-processes=<N>
+
+ The maximum number of worker processes. nghttpx spawns
+ new worker process when it reloads its configuration.
+ The previous worker process enters graceful termination
+ period and will terminate when it finishes handling the
+ existing connections. However, if reloading
+ configurations happen very frequently, the worker
+ processes might be piled up if they take a bit long time
+ to finish the existing connections. With this option,
+ if the number of worker processes exceeds the given
+ value, the oldest worker process is terminated
+ immediately. Specifying 0 means no limit and it is the
+ default behaviour.
+
+.. option:: --worker-process-grace-shutdown-period=<DURATION>
+
+ Maximum period for a worker process to terminate
+ gracefully. When a worker process enters in graceful
+ shutdown period (e.g., when nghttpx reloads its
+ configuration) and it does not finish handling the
+ existing connections in the given period of time, it is
+ immediately terminated. Specifying 0 means no limit and
+ it is the default behaviour.
+
+
+Scripting
+~~~~~~~~~
+
+.. option:: --mruby-file=<PATH>
+
+ Set mruby script file
+
+.. option:: --ignore-per-pattern-mruby-error
+
+ Ignore mruby compile error for per-pattern mruby script
+ file. If error occurred, it is treated as if no mruby
+ file were specified for the pattern.
+
+
+HTTP/3 and QUIC
+~~~~~~~~~~~~~~~
+
+.. option:: --frontend-quic-idle-timeout=<DURATION>
+
+ Specify an idle timeout for QUIC connection.
+
+ Default: ``30s``
+
+.. option:: --frontend-quic-debug-log
+
+ Output QUIC debug log to */dev/stderr.*
+
+.. option:: --quic-bpf-program-file=<PATH>
+
+ Specify a path to eBPF program file reuseport_kern.o to
+ direct an incoming QUIC UDP datagram to a correct
+ socket.
+
+ Default: ``/usr/local/lib/nghttp2/reuseport_kern.o``
+
+.. option:: --frontend-quic-early-data
+
+ Enable early data on frontend QUIC connections. nghttpx
+ sends "Early-Data" header field to a backend server if a
+ request is received in early data and handshake has not
+ finished. All backend servers should deal with possibly
+ replayed requests.
+
+.. option:: --frontend-quic-qlog-dir=<DIR>
+
+ Specify a directory where a qlog file is written for
+ frontend QUIC connections. A qlog file is created per
+ each QUIC connection. The file name is ISO8601 basic
+ format, followed by "-", server Source Connection ID and
+ ".sqlog".
+
+.. option:: --frontend-quic-require-token
+
+ Require an address validation token for a frontend QUIC
+ connection. Server sends a token in Retry packet or
+ NEW_TOKEN frame in the previous connection.
+
+.. option:: --frontend-quic-congestion-controller=<CC>
+
+ Specify a congestion controller algorithm for a frontend
+ QUIC connection. <CC> should be either "cubic" or
+ "bbr".
+
+ Default: ``cubic``
+
+.. option:: --frontend-quic-secret-file=<PATH>
+
+ Path to file that contains secure random data to be used
+ as QUIC keying materials. It is used to derive keys for
+ encrypting tokens and Connection IDs. It is not used to
+ encrypt QUIC packets. Each line of this file must
+ contain exactly 136 bytes hex-encoded string (when
+ decoded the byte string is 68 bytes long). The first 2
+ bits of decoded byte string are used to identify the
+ keying material. An empty line or a line which starts
+ '#' is ignored. The file can contain more than one
+ keying materials. Because the identifier is 2 bits, at
+ most 4 keying materials are read and the remaining data
+ is discarded. The first keying material in the file is
+ primarily used for encryption and decryption for new
+ connection. The other ones are used to decrypt data for
+ the existing connections. Specifying multiple keying
+ materials enables key rotation. Please note that key
+ rotation does not occur automatically. User should
+ update files or change options values and restart
+ nghttpx gracefully. If opening or reading given file
+ fails, all loaded keying materials are discarded and it
+ is treated as if none of this option is given. If this
+ option is not given or an error occurred while opening
+ or reading a file, a keying material is generated
+ internally on startup and reload.
+
+.. option:: --quic-server-id=<HEXSTRING>
+
+ Specify server ID encoded in Connection ID to identify
+ this particular server instance. Connection ID is
+ encrypted and this part is not visible in public. It
+ must be 4 bytes long and must be encoded in hex string
+ (which is 8 bytes long). If this option is omitted, a
+ random server ID is generated on startup and
+ configuration reload.
+
+.. option:: --frontend-quic-initial-rtt=<DURATION>
+
+ Specify the initial RTT of the frontend QUIC connection.
+
+ Default: ``333ms``
+
+.. option:: --no-quic-bpf
+
+ Disable eBPF.
+
+.. option:: --frontend-http3-window-size=<SIZE>
+
+ Sets the per-stream initial window size of HTTP/3
+ frontend connection.
+
+ Default: ``256K``
+
+.. option:: --frontend-http3-connection-window-size=<SIZE>
+
+ Sets the per-connection window size of HTTP/3 frontend
+ connection.
+
+ Default: ``1M``
+
+.. option:: --frontend-http3-max-window-size=<SIZE>
+
+ Sets the maximum per-stream window size of HTTP/3
+ frontend connection. The window size is adjusted based
+ on the receiving rate of stream data. The initial value
+ is the value specified by :option:`--frontend-http3-window-size`
+ and the window size grows up to <SIZE> bytes.
+
+ Default: ``6M``
+
+.. option:: --frontend-http3-max-connection-window-size=<SIZE>
+
+ Sets the maximum per-connection window size of HTTP/3
+ frontend connection. The window size is adjusted based
+ on the receiving rate of stream data. The initial value
+ is the value specified by
+ :option:`--frontend-http3-connection-window-size` and the window
+ size grows up to <SIZE> bytes.
+
+ Default: ``8M``
+
+.. option:: --frontend-http3-max-concurrent-streams=<N>
+
+ Set the maximum number of the concurrent streams in one
+ frontend HTTP/3 connection.
+
+ Default: ``100``
+
+
+Misc
+~~~~
+
+.. option:: --conf=<PATH>
+
+ Load configuration from <PATH>. Please note that
+ nghttpx always tries to read the default configuration
+ file if :option:`--conf` is not given.
+
+ Default: ``/etc/nghttpx/nghttpx.conf``
+
+.. option:: --include=<PATH>
+
+ Load additional configurations from <PATH>. File <PATH>
+ is read when configuration parser encountered this
+ option. This option can be used multiple times, or even
+ recursively.
+
+.. option:: -v, --version
+
+ Print version and exit.
+
+.. option:: -h, --help
+
+ Print this help and exit.
+
+
+
+The <SIZE> argument is an integer and an optional unit (e.g., 10K is
+10 * 1024). Units are K, M and G (powers of 1024).
+
+The <DURATION> argument is an integer and an optional unit (e.g., 1s
+is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
+(hours, minutes, seconds and milliseconds, respectively). If a unit
+is omitted, a second is used as unit.
+
+FILES
+-----
+
+*/etc/nghttpx/nghttpx.conf*
+ The default configuration file path nghttpx searches at startup.
+ The configuration file path can be changed using :option:`--conf`
+ option.
+
+ Those lines which are staring ``#`` are treated as comment.
+
+ The option name in the configuration file is the long command-line
+ option name with leading ``--`` stripped (e.g., ``frontend``). Put
+ ``=`` between option name and value. Don't put extra leading or
+ trailing spaces.
+
+ When specifying arguments including characters which have special
+ meaning to a shell, we usually use quotes so that shell does not
+ interpret them. When writing this configuration file, quotes for
+ this purpose must not be used. For example, specify additional
+ request header field, do this:
+
+ .. code-block:: text
+
+ add-request-header=foo: bar
+
+ instead of:
+
+ .. code-block:: text
+
+ add-request-header="foo: bar"
+
+ The options which do not take argument in the command-line *take*
+ argument in the configuration file. Specify ``yes`` as an argument
+ (e.g., ``http2-proxy=yes``). If other string is given, it is
+ ignored.
+
+ To specify private key and certificate file which are given as
+ positional arguments in command-line, use ``private-key-file`` and
+ ``certificate-file``.
+
+ :option:`--conf` option cannot be used in the configuration file and
+ will be ignored if specified.
+
+Error log
+ Error log is written to stderr by default. It can be configured
+ using :option:`--errorlog-file`. The format of log message is as
+ follows:
+
+ <datetime> <main-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
+
+ <datetime>
+ It is a combination of date and time when the log is written. It
+ is in ISO 8601 format.
+
+ <main-pid>
+ It is a main process ID.
+
+ <current-pid>
+ It is a process ID which writes this log.
+
+ <thread-id>
+ It is a thread ID which writes this log. It would be unique
+ within <current-pid>.
+
+ <filename> and <line>
+ They are source file name, and line number which produce this log.
+
+ <msg>
+ It is a log message body.
+
+SIGNALS
+-------
+
+SIGQUIT
+ Shutdown gracefully. First accept pending connections and stop
+ accepting connection. After all connections are handled, nghttpx
+ exits.
+
+SIGHUP
+ Reload configuration file given in :option:`--conf`.
+
+SIGUSR1
+ Reopen log files.
+
+SIGUSR2
+
+ Fork and execute nghttpx. It will execute the binary in the same
+ path with same command-line arguments and environment variables. As
+ of nghttpx version 1.20.0, the new main process sends SIGQUIT to the
+ original main process when it is ready to serve requests. For the
+ earlier versions of nghttpx, user has to send SIGQUIT to the
+ original main process.
+
+ The difference between SIGUSR2 (+ SIGQUIT) and SIGHUP is that former
+ is usually used to execute new binary, and the main process is newly
+ spawned. On the other hand, the latter just reloads configuration
+ file, and the same main process continues to exist.
+
+.. note::
+
+ nghttpx consists of multiple processes: one process for processing
+ these signals, and another one for processing requests. The former
+ spawns the latter. The former is called main process, and the
+ latter is called worker process. If neverbleed is enabled, the
+ worker process spawns neverbleed daemon process which does RSA key
+ processing. The above signal must be sent to the main process. If
+ the other processes received one of them, it is ignored. This
+ behaviour of these processes may change in the future release. In
+ other words, in the future release, the processes other than main
+ process may terminate upon the reception of these signals.
+ Therefore these signals should not be sent to the processes other
+ than main process.
+
+SERVER PUSH
+-----------
+
+nghttpx supports HTTP/2 server push in default mode with Link header
+field. nghttpx looks for Link header field (`RFC 5988
+<http://tools.ietf.org/html/rfc5988>`_) in response headers from
+backend server and extracts URI-reference with parameter
+``rel=preload`` (see `preload
+<http://w3c.github.io/preload/#interoperability-with-http-link-header>`_)
+and pushes those URIs to the frontend client. Here is a sample Link
+header field to initiate server push:
+
+.. code-block:: text
+
+ Link: </fonts/font.woff>; rel=preload
+ Link: </css/theme.css>; rel=preload
+
+Currently, the following restriction is applied for server push:
+
+1. The associated stream must have method "GET" or "POST". The
+ associated stream's status code must be 200.
+
+This limitation may be loosened in the future release.
+
+nghttpx also supports server push if both frontend and backend are
+HTTP/2 in default mode. In this case, in addition to server push via
+Link header field, server push from backend is forwarded to frontend
+HTTP/2 session.
+
+HTTP/2 server push will be disabled if :option:`--http2-proxy` is
+used.
+
+UNIX DOMAIN SOCKET
+------------------
+
+nghttpx supports UNIX domain socket with a filename for both frontend
+and backend connections.
+
+Please note that current nghttpx implementation does not delete a
+socket with a filename. And on start up, if nghttpx detects that the
+specified socket already exists in the file system, nghttpx first
+deletes it. However, if SIGUSR2 is used to execute new binary and
+both old and new configurations use same filename, new binary does not
+delete the socket and continues to use it.
+
+OCSP STAPLING
+-------------
+
+OCSP query is done using external Python script
+``fetch-ocsp-response``, which has been originally developed in Perl
+as part of h2o project (https://github.com/h2o/h2o), and was
+translated into Python.
+
+The script file is usually installed under
+``$(prefix)/share/nghttp2/`` directory. The actual path to script can
+be customized using :option:`--fetch-ocsp-response-file` option.
+
+If OCSP query is failed, previous OCSP response, if any, is continued
+to be used.
+
+:option:`--fetch-ocsp-response-file` option provides wide range of
+possibility to manage OCSP response. It can take an arbitrary script
+or executable. The requirement is that it supports the command-line
+interface of ``fetch-ocsp-response`` script, and it must return a
+valid DER encoded OCSP response on success. It must return exit code
+0 on success, and 75 for temporary error, and the other error code for
+generic failure. For large cluster of servers, it is not efficient
+for each server to perform OCSP query using ``fetch-ocsp-response``.
+Instead, you can retrieve OCSP response in some way, and store it in a
+disk or a shared database. Then specify a program in
+:option:`--fetch-ocsp-response-file` to fetch it from those stores.
+This could provide a way to share the OCSP response between fleet of
+servers, and also any OCSP query strategy can be applied which may be
+beyond the ability of nghttpx itself or ``fetch-ocsp-response``
+script.
+
+TLS SESSION RESUMPTION
+----------------------
+
+nghttpx supports TLS session resumption through both session ID and
+session ticket.
+
+SESSION ID RESUMPTION
+~~~~~~~~~~~~~~~~~~~~~
+
+By default, session ID is shared by all worker threads.
+
+If :option:`--tls-session-cache-memcached` is given, nghttpx will
+insert serialized session data to memcached with
+``nghttpx:tls-session-cache:`` + lowercase hex string of session ID
+as a memcached entry key, with expiry time 12 hours. Session timeout
+is set to 12 hours.
+
+By default, connections to memcached server are not encrypted. To
+enable encryption, use ``tls`` keyword in
+:option:`--tls-session-cache-memcached` option.
+
+TLS SESSION TICKET RESUMPTION
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, session ticket is shared by all worker threads. The
+automatic key rotation is also enabled by default. Every an hour, new
+encryption key is generated, and previous encryption key becomes
+decryption only key. We set session timeout to 12 hours, and thus we
+keep at most 12 keys.
+
+If :option:`--tls-ticket-key-memcached` is given, encryption keys are
+retrieved from memcached. nghttpx just reads keys from memcached; one
+has to deploy key generator program to update keys frequently (e.g.,
+every 1 hour). The example key generator tlsticketupdate.go is
+available under contrib directory in nghttp2 archive. The memcached
+entry key is ``nghttpx:tls-ticket-key``. The data format stored in
+memcached is the binary format described below:
+
+.. code-block:: text
+
+ +--------------+-------+----------------+
+ | VERSION (4) |LEN (2)|KEY(48 or 80) ...
+ +--------------+-------+----------------+
+ ^ |
+ | |
+ +------------------------+
+ (LEN, KEY) pair can be repeated
+
+All numbers in the above figure is bytes. All integer fields are
+network byte order.
+
+First 4 bytes integer VERSION field, which must be 1. The 2 bytes
+integer LEN field gives the length of following KEY field, which
+contains key. If :option:`--tls-ticket-key-cipher`\=aes-128-cbc is
+used, LEN must be 48. If
+:option:`--tls-ticket-key-cipher`\=aes-256-cbc is used, LEN must be
+80. LEN and KEY pair can be repeated multiple times to store multiple
+keys. The key appeared first is used as encryption key. All the
+remaining keys are used as decryption only.
+
+By default, connections to memcached server are not encrypted. To
+enable encryption, use ``tls`` keyword in
+:option:`--tls-ticket-key-memcached` option.
+
+If :option:`--tls-ticket-key-file` is given, encryption key is read
+from the given file. In this case, nghttpx does not rotate key
+automatically. To rotate key, one has to restart nghttpx (see
+SIGNALS).
+
+CERTIFICATE TRANSPARENCY
+------------------------
+
+nghttpx supports TLS ``signed_certificate_timestamp`` extension (`RFC
+6962 <https://tools.ietf.org/html/rfc6962>`_). The relevant options
+are :option:`--tls-sct-dir` and ``sct-dir`` parameter in
+:option:`--subcert`. They takes a directory, and nghttpx reads all
+files whose extension is ``.sct`` under the directory. The ``*.sct``
+files are encoded as ``SignedCertificateTimestamp`` struct described
+in `section 3.2 of RFC 69662
+<https://tools.ietf.org/html/rfc6962#section-3.2>`_. This format is
+the same one used by `nginx-ct
+<https://github.com/grahamedgecombe/nginx-ct>`_ and `mod_ssl_ct
+<https://httpd.apache.org/docs/trunk/mod/mod_ssl_ct.html>`_.
+`ct-submit <https://github.com/grahamedgecombe/ct-submit>`_ can be
+used to submit certificates to log servers, and obtain the
+``SignedCertificateTimestamp`` struct which can be used with nghttpx.
+
+MRUBY SCRIPTING
+---------------
+
+.. warning::
+
+ The current mruby extension API is experimental and not frozen. The
+ API is subject to change in the future release.
+
+.. warning::
+
+ Almost all string value returned from method, or attribute is a
+ fresh new mruby string, which involves memory allocation, and
+ copies. Therefore, it is strongly recommended to store a return
+ value in a local variable, and use it, instead of calling method or
+ accessing attribute repeatedly.
+
+nghttpx allows users to extend its capability using mruby scripts.
+nghttpx has 2 hook points to execute mruby script: request phase and
+response phase. The request phase hook is invoked after all request
+header fields are received from client. The response phase hook is
+invoked after all response header fields are received from backend
+server. These hooks allows users to modify header fields, or common
+HTTP variables, like authority or request path, and even return custom
+response without forwarding request to backend servers.
+
+There are 2 levels of mruby script invocations: global and
+per-pattern. The global mruby script is set by :option:`--mruby-file`
+option and is called for all requests. The per-pattern mruby script
+is set by "mruby" parameter in :option:`-b` option. It is invoked for
+a request which matches the particular pattern. The order of hook
+invocation is: global request phase hook, per-pattern request phase
+hook, per-pattern response phase hook, and finally global response
+phase hook. If a hook returns a response, any later hooks are not
+invoked. The global request hook is invoked before the pattern
+matching is made and changing request path may affect the pattern
+matching.
+
+Please note that request and response hooks of per-pattern mruby
+script for a single request might not come from the same script. This
+might happen after a request hook is executed, backend failed for some
+reason, and at the same time, backend configuration is replaced by API
+request, and then the request uses new configuration on retry. The
+response hook from new configuration, if it is specified, will be
+invoked.
+
+The all mruby script will be evaluated once per thread on startup, and
+it must instantiate object and evaluate it as the return value (e.g.,
+``App.new``). This object is called app object. If app object
+defines ``on_req`` method, it is called with :rb:class:`Nghttpx::Env`
+object on request hook. Similarly, if app object defines ``on_resp``
+method, it is called with :rb:class:`Nghttpx::Env` object on response
+hook. For each method invocation, user can can access
+:rb:class:`Nghttpx::Request` and :rb:class:`Nghttpx::Response` objects
+via :rb:attr:`Nghttpx::Env#req` and :rb:attr:`Nghttpx::Env#resp`
+respectively.
+
+.. rb:module:: Nghttpx
+
+.. rb:const:: REQUEST_PHASE
+
+ Constant to represent request phase.
+
+.. rb:const:: RESPONSE_PHASE
+
+ Constant to represent response phase.
+
+.. rb:class:: Env
+
+ Object to represent current request specific context.
+
+ .. rb:attr_reader:: req
+
+ Return :rb:class:`Request` object.
+
+ .. rb:attr_reader:: resp
+
+ Return :rb:class:`Response` object.
+
+ .. rb:attr_reader:: ctx
+
+ Return Ruby hash object. It persists until request finishes.
+ So values set in request phase hook can be retrieved in
+ response phase hook.
+
+ .. rb:attr_reader:: phase
+
+ Return the current phase.
+
+ .. rb:attr_reader:: remote_addr
+
+ Return IP address of a remote client. If connection is made
+ via UNIX domain socket, this returns the string "localhost".
+
+ .. rb:attr_reader:: server_addr
+
+ Return address of server that accepted the connection. This
+ is a string which specified in :option:`--frontend` option,
+ excluding port number, and not a resolved IP address. For
+ UNIX domain socket, this is a path to UNIX domain socket.
+
+ .. rb:attr_reader:: server_port
+
+ Return port number of the server frontend which accepted the
+ connection from client.
+
+ .. rb:attr_reader:: tls_used
+
+ Return true if TLS is used on the connection.
+
+ .. rb:attr_reader:: tls_sni
+
+ Return the TLS SNI value which client sent in this connection.
+
+ .. rb:attr_reader:: tls_client_fingerprint_sha256
+
+ Return the SHA-256 fingerprint of a client certificate.
+
+ .. rb:attr_reader:: tls_client_fingerprint_sha1
+
+ Return the SHA-1 fingerprint of a client certificate.
+
+ .. rb:attr_reader:: tls_client_issuer_name
+
+ Return the issuer name of a client certificate.
+
+ .. rb:attr_reader:: tls_client_subject_name
+
+ Return the subject name of a client certificate.
+
+ .. rb:attr_reader:: tls_client_serial
+
+ Return the serial number of a client certificate.
+
+ .. rb:attr_reader:: tls_client_not_before
+
+ Return the start date of a client certificate in seconds since
+ the epoch.
+
+ .. rb:attr_reader:: tls_client_not_after
+
+ Return the end date of a client certificate in seconds since
+ the epoch.
+
+ .. rb:attr_reader:: tls_cipher
+
+ Return a TLS cipher negotiated in this connection.
+
+ .. rb:attr_reader:: tls_protocol
+
+ Return a TLS protocol version negotiated in this connection.
+
+ .. rb:attr_reader:: tls_session_id
+
+ Return a session ID for this connection in hex string.
+
+ .. rb:attr_reader:: tls_session_reused
+
+ Return true if, and only if a SSL/TLS session is reused.
+
+ .. rb:attr_reader:: alpn
+
+ Return ALPN identifier negotiated in this connection.
+
+ .. rb:attr_reader:: tls_handshake_finished
+
+ Return true if SSL/TLS handshake has finished. If it returns
+ false in the request phase hook, the request is received in
+ TLSv1.3 early data (0-RTT) and might be vulnerable to the
+ replay attack. nghttpx will send Early-Data header field to
+ backend servers to indicate this.
+
+.. rb:class:: Request
+
+ Object to represent request from client. The modification to
+ Request object is allowed only in request phase hook.
+
+ .. rb:attr_reader:: http_version_major
+
+ Return HTTP major version.
+
+ .. rb:attr_reader:: http_version_minor
+
+ Return HTTP minor version.
+
+ .. rb:attr_accessor:: method
+
+ HTTP method. On assignment, copy of given value is assigned.
+ We don't accept arbitrary method name. We will document them
+ later, but well known methods, like GET, PUT and POST, are all
+ supported.
+
+ .. rb:attr_accessor:: authority
+
+ Authority (i.e., example.org), including optional port
+ component . On assignment, copy of given value is assigned.
+
+ .. rb:attr_accessor:: scheme
+
+ Scheme (i.e., http, https). On assignment, copy of given
+ value is assigned.
+
+ .. rb:attr_accessor:: path
+
+ Request path, including query component (i.e., /index.html).
+ On assignment, copy of given value is assigned. The path does
+ not include authority component of URI. This may include
+ query component. nghttpx makes certain normalization for
+ path. It decodes percent-encoding for unreserved characters
+ (see https://tools.ietf.org/html/rfc3986#section-2.3), and
+ resolves ".." and ".". But it may leave characters which
+ should be percent-encoded as is. So be careful when comparing
+ path against desired string.
+
+ .. rb:attr_reader:: headers
+
+ Return Ruby hash containing copy of request header fields.
+ Changing values in returned hash does not change request
+ header fields actually used in request processing. Use
+ :rb:meth:`Nghttpx::Request#add_header` or
+ :rb:meth:`Nghttpx::Request#set_header` to change request
+ header fields.
+
+ .. rb:method:: add_header(key, value)
+
+ Add header entry associated with key. The value can be single
+ string or array of string. It does not replace any existing
+ values associated with key.
+
+ .. rb:method:: set_header(key, value)
+
+ Set header entry associated with key. The value can be single
+ string or array of string. It replaces any existing values
+ associated with key.
+
+ .. rb:method:: clear_headers
+
+ Clear all existing request header fields.
+
+ .. rb:method:: push(uri)
+
+ Initiate to push resource identified by *uri*. Only HTTP/2
+ protocol supports this feature. For the other protocols, this
+ method is noop. *uri* can be absolute URI, absolute path or
+ relative path to the current request. For absolute or
+ relative path, scheme and authority are inherited from the
+ current request. Currently, method is always GET. nghttpx
+ will issue request to backend servers to fulfill this request.
+ The request and response phase hooks will be called for pushed
+ resource as well.
+
+.. rb:class:: Response
+
+ Object to represent response from backend server.
+
+ .. rb:attr_reader:: http_version_major
+
+ Return HTTP major version.
+
+ .. rb:attr_reader:: http_version_minor
+
+ Return HTTP minor version.
+
+ .. rb:attr_accessor:: status
+
+ HTTP status code. It must be in the range [200, 999],
+ inclusive. The non-final status code is not supported in
+ mruby scripting at the moment.
+
+ .. rb:attr_reader:: headers
+
+ Return Ruby hash containing copy of response header fields.
+ Changing values in returned hash does not change response
+ header fields actually used in response processing. Use
+ :rb:meth:`Nghttpx::Response#add_header` or
+ :rb:meth:`Nghttpx::Response#set_header` to change response
+ header fields.
+
+ .. rb:method:: add_header(key, value)
+
+ Add header entry associated with key. The value can be single
+ string or array of string. It does not replace any existing
+ values associated with key.
+
+ .. rb:method:: set_header(key, value)
+
+ Set header entry associated with key. The value can be single
+ string or array of string. It replaces any existing values
+ associated with key.
+
+ .. rb:method:: clear_headers
+
+ Clear all existing response header fields.
+
+ .. rb:method:: return(body)
+
+ Return custom response *body* to a client. When this method
+ is called in request phase hook, the request is not forwarded
+ to the backend, and response phase hook for this request will
+ not be invoked. When this method is called in response phase
+ hook, response from backend server is canceled and discarded.
+ The status code and response header fields should be set
+ before using this method. To set status code, use
+ :rb:attr:`Nghttpx::Response#status`. If status code is not
+ set, 200 is used. To set response header fields,
+ :rb:meth:`Nghttpx::Response#add_header` and
+ :rb:meth:`Nghttpx::Response#set_header`. When this method is
+ invoked in response phase hook, the response headers are
+ filled with the ones received from backend server. To send
+ completely custom header fields, first call
+ :rb:meth:`Nghttpx::Response#clear_headers` to erase all
+ existing header fields, and then add required header fields.
+ It is an error to call this method twice for a given request.
+
+ .. rb:method:: send_info(status, headers)
+
+ Send non-final (informational) response to a client. *status*
+ must be in the range [100, 199], inclusive. *headers* is a
+ hash containing response header fields. Its key must be a
+ string, and the associated value must be either string or
+ array of strings. Since this is not a final response, even if
+ this method is invoked, request is still forwarded to a
+ backend unless :rb:meth:`Nghttpx::Response#return` is called.
+ This method can be called multiple times. It cannot be called
+ after :rb:meth:`Nghttpx::Response#return` is called.
+
+MRUBY EXAMPLES
+~~~~~~~~~~~~~~
+
+Modify request path:
+
+.. code-block:: ruby
+
+ class App
+ def on_req(env)
+ env.req.path = "/apps#{env.req.path}"
+ end
+ end
+
+ App.new
+
+Don't forget to instantiate and evaluate object at the last line.
+
+Restrict permission of viewing a content to a specific client
+addresses:
+
+.. code-block:: ruby
+
+ class App
+ def on_req(env)
+ allowed_clients = ["127.0.0.1", "::1"]
+
+ if env.req.path.start_with?("/log/") &&
+ !allowed_clients.include?(env.remote_addr) then
+ env.resp.status = 404
+ env.resp.return "permission denied"
+ end
+ end
+ end
+
+ App.new
+
+API ENDPOINTS
+-------------
+
+nghttpx exposes API endpoints to manipulate it via HTTP based API. By
+default, API endpoint is disabled. To enable it, add a dedicated
+frontend for API using :option:`--frontend` option with "api"
+parameter. All requests which come from this frontend address, will
+be treated as API request.
+
+The response is normally JSON dictionary, and at least includes the
+following keys:
+
+status
+ The status of the request processing. The following values are
+ defined:
+
+ Success
+ The request was successful.
+
+ Failure
+ The request was failed. No change has been made.
+
+code
+ HTTP status code
+
+Additionally, depending on the API endpoint, ``data`` key may be
+present, and its value contains the API endpoint specific data.
+
+We wrote "normally", since nghttpx may return ordinal HTML response in
+some cases where the error has occurred before reaching API endpoint
+(e.g., header field is too large).
+
+The following section describes available API endpoints.
+
+POST /api/v1beta1/backendconfig
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This API replaces the current backend server settings with the
+requested ones. The request method should be POST, but PUT is also
+acceptable. The request body must be nghttpx configuration file
+format. For configuration file format, see `FILES`_ section. The
+line separator inside the request body must be single LF (0x0A).
+Currently, only :option:`backend <--backend>` option is parsed, the
+others are simply ignored. The semantics of this API is replace the
+current backend with the backend options in request body. Describe
+the desired set of backend severs, and nghttpx makes it happen. If
+there is no :option:`backend <--backend>` option is found in request
+body, the current set of backend is replaced with the :option:`backend
+<--backend>` option's default value, which is ``127.0.0.1,80``.
+
+The replacement is done instantly without breaking existing
+connections or requests. It also avoids any process creation as is
+the case with hot swapping with signals.
+
+The one limitation is that only numeric IP address is allowed in
+:option:`backend <--backend>` in request body unless "dns" parameter
+is used while non numeric hostname is allowed in command-line or
+configuration file is read using :option:`--conf`.
+
+GET /api/v1beta1/configrevision
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This API returns configuration revision of the current nghttpx. The
+configuration revision is opaque string, and it changes after each
+reloading by SIGHUP. With this API, an external application knows
+that whether nghttpx has finished reloading its configuration by
+comparing the configuration revisions between before and after
+reloading. It is recommended to disable persistent (keep-alive)
+connection for this purpose in order to avoid to send a request using
+the reused connection which may bound to an old process.
+
+This API returns response including ``data`` key. Its value is JSON
+object, and it contains at least the following key:
+
+configRevision
+ The configuration revision of the current nghttpx
+
+
+SEE ALSO
+--------
+
+:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`h2load(1)`
diff --git a/doc/nghttpx.h2r b/doc/nghttpx.h2r
new file mode 100644
index 0000000..12ac718
--- /dev/null
+++ b/doc/nghttpx.h2r
@@ -0,0 +1,719 @@
+FILES
+-----
+
+*/etc/nghttpx/nghttpx.conf*
+ The default configuration file path nghttpx searches at startup.
+ The configuration file path can be changed using :option:`--conf`
+ option.
+
+ Those lines which are staring ``#`` are treated as comment.
+
+ The option name in the configuration file is the long command-line
+ option name with leading ``--`` stripped (e.g., ``frontend``). Put
+ ``=`` between option name and value. Don't put extra leading or
+ trailing spaces.
+
+ When specifying arguments including characters which have special
+ meaning to a shell, we usually use quotes so that shell does not
+ interpret them. When writing this configuration file, quotes for
+ this purpose must not be used. For example, specify additional
+ request header field, do this:
+
+ .. code-block:: text
+
+ add-request-header=foo: bar
+
+ instead of:
+
+ .. code-block:: text
+
+ add-request-header="foo: bar"
+
+ The options which do not take argument in the command-line *take*
+ argument in the configuration file. Specify ``yes`` as an argument
+ (e.g., ``http2-proxy=yes``). If other string is given, it is
+ ignored.
+
+ To specify private key and certificate file which are given as
+ positional arguments in command-line, use ``private-key-file`` and
+ ``certificate-file``.
+
+ :option:`--conf` option cannot be used in the configuration file and
+ will be ignored if specified.
+
+Error log
+ Error log is written to stderr by default. It can be configured
+ using :option:`--errorlog-file`. The format of log message is as
+ follows:
+
+ <datetime> <main-pid> <current-pid> <thread-id> <level> (<filename>:<line>) <msg>
+
+ <datetime>
+ It is a combination of date and time when the log is written. It
+ is in ISO 8601 format.
+
+ <main-pid>
+ It is a main process ID.
+
+ <current-pid>
+ It is a process ID which writes this log.
+
+ <thread-id>
+ It is a thread ID which writes this log. It would be unique
+ within <current-pid>.
+
+ <filename> and <line>
+ They are source file name, and line number which produce this log.
+
+ <msg>
+ It is a log message body.
+
+SIGNALS
+-------
+
+SIGQUIT
+ Shutdown gracefully. First accept pending connections and stop
+ accepting connection. After all connections are handled, nghttpx
+ exits.
+
+SIGHUP
+ Reload configuration file given in :option:`--conf`.
+
+SIGUSR1
+ Reopen log files.
+
+SIGUSR2
+
+ Fork and execute nghttpx. It will execute the binary in the same
+ path with same command-line arguments and environment variables. As
+ of nghttpx version 1.20.0, the new main process sends SIGQUIT to the
+ original main process when it is ready to serve requests. For the
+ earlier versions of nghttpx, user has to send SIGQUIT to the
+ original main process.
+
+ The difference between SIGUSR2 (+ SIGQUIT) and SIGHUP is that former
+ is usually used to execute new binary, and the main process is newly
+ spawned. On the other hand, the latter just reloads configuration
+ file, and the same main process continues to exist.
+
+.. note::
+
+ nghttpx consists of multiple processes: one process for processing
+ these signals, and another one for processing requests. The former
+ spawns the latter. The former is called main process, and the
+ latter is called worker process. If neverbleed is enabled, the
+ worker process spawns neverbleed daemon process which does RSA key
+ processing. The above signal must be sent to the main process. If
+ the other processes received one of them, it is ignored. This
+ behaviour of these processes may change in the future release. In
+ other words, in the future release, the processes other than main
+ process may terminate upon the reception of these signals.
+ Therefore these signals should not be sent to the processes other
+ than main process.
+
+SERVER PUSH
+-----------
+
+nghttpx supports HTTP/2 server push in default mode with Link header
+field. nghttpx looks for Link header field (`RFC 5988
+<http://tools.ietf.org/html/rfc5988>`_) in response headers from
+backend server and extracts URI-reference with parameter
+``rel=preload`` (see `preload
+<http://w3c.github.io/preload/#interoperability-with-http-link-header>`_)
+and pushes those URIs to the frontend client. Here is a sample Link
+header field to initiate server push:
+
+.. code-block:: text
+
+ Link: </fonts/font.woff>; rel=preload
+ Link: </css/theme.css>; rel=preload
+
+Currently, the following restriction is applied for server push:
+
+1. The associated stream must have method "GET" or "POST". The
+ associated stream's status code must be 200.
+
+This limitation may be loosened in the future release.
+
+nghttpx also supports server push if both frontend and backend are
+HTTP/2 in default mode. In this case, in addition to server push via
+Link header field, server push from backend is forwarded to frontend
+HTTP/2 session.
+
+HTTP/2 server push will be disabled if :option:`--http2-proxy` is
+used.
+
+UNIX DOMAIN SOCKET
+------------------
+
+nghttpx supports UNIX domain socket with a filename for both frontend
+and backend connections.
+
+Please note that current nghttpx implementation does not delete a
+socket with a filename. And on start up, if nghttpx detects that the
+specified socket already exists in the file system, nghttpx first
+deletes it. However, if SIGUSR2 is used to execute new binary and
+both old and new configurations use same filename, new binary does not
+delete the socket and continues to use it.
+
+OCSP STAPLING
+-------------
+
+OCSP query is done using external Python script
+``fetch-ocsp-response``, which has been originally developed in Perl
+as part of h2o project (https://github.com/h2o/h2o), and was
+translated into Python.
+
+The script file is usually installed under
+``$(prefix)/share/nghttp2/`` directory. The actual path to script can
+be customized using :option:`--fetch-ocsp-response-file` option.
+
+If OCSP query is failed, previous OCSP response, if any, is continued
+to be used.
+
+:option:`--fetch-ocsp-response-file` option provides wide range of
+possibility to manage OCSP response. It can take an arbitrary script
+or executable. The requirement is that it supports the command-line
+interface of ``fetch-ocsp-response`` script, and it must return a
+valid DER encoded OCSP response on success. It must return exit code
+0 on success, and 75 for temporary error, and the other error code for
+generic failure. For large cluster of servers, it is not efficient
+for each server to perform OCSP query using ``fetch-ocsp-response``.
+Instead, you can retrieve OCSP response in some way, and store it in a
+disk or a shared database. Then specify a program in
+:option:`--fetch-ocsp-response-file` to fetch it from those stores.
+This could provide a way to share the OCSP response between fleet of
+servers, and also any OCSP query strategy can be applied which may be
+beyond the ability of nghttpx itself or ``fetch-ocsp-response``
+script.
+
+TLS SESSION RESUMPTION
+----------------------
+
+nghttpx supports TLS session resumption through both session ID and
+session ticket.
+
+SESSION ID RESUMPTION
+~~~~~~~~~~~~~~~~~~~~~
+
+By default, session ID is shared by all worker threads.
+
+If :option:`--tls-session-cache-memcached` is given, nghttpx will
+insert serialized session data to memcached with
+``nghttpx:tls-session-cache:`` + lowercase hex string of session ID
+as a memcached entry key, with expiry time 12 hours. Session timeout
+is set to 12 hours.
+
+By default, connections to memcached server are not encrypted. To
+enable encryption, use ``tls`` keyword in
+:option:`--tls-session-cache-memcached` option.
+
+TLS SESSION TICKET RESUMPTION
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, session ticket is shared by all worker threads. The
+automatic key rotation is also enabled by default. Every an hour, new
+encryption key is generated, and previous encryption key becomes
+decryption only key. We set session timeout to 12 hours, and thus we
+keep at most 12 keys.
+
+If :option:`--tls-ticket-key-memcached` is given, encryption keys are
+retrieved from memcached. nghttpx just reads keys from memcached; one
+has to deploy key generator program to update keys frequently (e.g.,
+every 1 hour). The example key generator tlsticketupdate.go is
+available under contrib directory in nghttp2 archive. The memcached
+entry key is ``nghttpx:tls-ticket-key``. The data format stored in
+memcached is the binary format described below:
+
+.. code-block:: text
+
+ +--------------+-------+----------------+
+ | VERSION (4) |LEN (2)|KEY(48 or 80) ...
+ +--------------+-------+----------------+
+ ^ |
+ | |
+ +------------------------+
+ (LEN, KEY) pair can be repeated
+
+All numbers in the above figure is bytes. All integer fields are
+network byte order.
+
+First 4 bytes integer VERSION field, which must be 1. The 2 bytes
+integer LEN field gives the length of following KEY field, which
+contains key. If :option:`--tls-ticket-key-cipher`\=aes-128-cbc is
+used, LEN must be 48. If
+:option:`--tls-ticket-key-cipher`\=aes-256-cbc is used, LEN must be
+80. LEN and KEY pair can be repeated multiple times to store multiple
+keys. The key appeared first is used as encryption key. All the
+remaining keys are used as decryption only.
+
+By default, connections to memcached server are not encrypted. To
+enable encryption, use ``tls`` keyword in
+:option:`--tls-ticket-key-memcached` option.
+
+If :option:`--tls-ticket-key-file` is given, encryption key is read
+from the given file. In this case, nghttpx does not rotate key
+automatically. To rotate key, one has to restart nghttpx (see
+SIGNALS).
+
+CERTIFICATE TRANSPARENCY
+------------------------
+
+nghttpx supports TLS ``signed_certificate_timestamp`` extension (`RFC
+6962 <https://tools.ietf.org/html/rfc6962>`_). The relevant options
+are :option:`--tls-sct-dir` and ``sct-dir`` parameter in
+:option:`--subcert`. They takes a directory, and nghttpx reads all
+files whose extension is ``.sct`` under the directory. The ``*.sct``
+files are encoded as ``SignedCertificateTimestamp`` struct described
+in `section 3.2 of RFC 69662
+<https://tools.ietf.org/html/rfc6962#section-3.2>`_. This format is
+the same one used by `nginx-ct
+<https://github.com/grahamedgecombe/nginx-ct>`_ and `mod_ssl_ct
+<https://httpd.apache.org/docs/trunk/mod/mod_ssl_ct.html>`_.
+`ct-submit <https://github.com/grahamedgecombe/ct-submit>`_ can be
+used to submit certificates to log servers, and obtain the
+``SignedCertificateTimestamp`` struct which can be used with nghttpx.
+
+MRUBY SCRIPTING
+---------------
+
+.. warning::
+
+ The current mruby extension API is experimental and not frozen. The
+ API is subject to change in the future release.
+
+.. warning::
+
+ Almost all string value returned from method, or attribute is a
+ fresh new mruby string, which involves memory allocation, and
+ copies. Therefore, it is strongly recommended to store a return
+ value in a local variable, and use it, instead of calling method or
+ accessing attribute repeatedly.
+
+nghttpx allows users to extend its capability using mruby scripts.
+nghttpx has 2 hook points to execute mruby script: request phase and
+response phase. The request phase hook is invoked after all request
+header fields are received from client. The response phase hook is
+invoked after all response header fields are received from backend
+server. These hooks allows users to modify header fields, or common
+HTTP variables, like authority or request path, and even return custom
+response without forwarding request to backend servers.
+
+There are 2 levels of mruby script invocations: global and
+per-pattern. The global mruby script is set by :option:`--mruby-file`
+option and is called for all requests. The per-pattern mruby script
+is set by "mruby" parameter in :option:`-b` option. It is invoked for
+a request which matches the particular pattern. The order of hook
+invocation is: global request phase hook, per-pattern request phase
+hook, per-pattern response phase hook, and finally global response
+phase hook. If a hook returns a response, any later hooks are not
+invoked. The global request hook is invoked before the pattern
+matching is made and changing request path may affect the pattern
+matching.
+
+Please note that request and response hooks of per-pattern mruby
+script for a single request might not come from the same script. This
+might happen after a request hook is executed, backend failed for some
+reason, and at the same time, backend configuration is replaced by API
+request, and then the request uses new configuration on retry. The
+response hook from new configuration, if it is specified, will be
+invoked.
+
+The all mruby script will be evaluated once per thread on startup, and
+it must instantiate object and evaluate it as the return value (e.g.,
+``App.new``). This object is called app object. If app object
+defines ``on_req`` method, it is called with :rb:class:`Nghttpx::Env`
+object on request hook. Similarly, if app object defines ``on_resp``
+method, it is called with :rb:class:`Nghttpx::Env` object on response
+hook. For each method invocation, user can can access
+:rb:class:`Nghttpx::Request` and :rb:class:`Nghttpx::Response` objects
+via :rb:attr:`Nghttpx::Env#req` and :rb:attr:`Nghttpx::Env#resp`
+respectively.
+
+.. rb:module:: Nghttpx
+
+.. rb:const:: REQUEST_PHASE
+
+ Constant to represent request phase.
+
+.. rb:const:: RESPONSE_PHASE
+
+ Constant to represent response phase.
+
+.. rb:class:: Env
+
+ Object to represent current request specific context.
+
+ .. rb:attr_reader:: req
+
+ Return :rb:class:`Request` object.
+
+ .. rb:attr_reader:: resp
+
+ Return :rb:class:`Response` object.
+
+ .. rb:attr_reader:: ctx
+
+ Return Ruby hash object. It persists until request finishes.
+ So values set in request phase hook can be retrieved in
+ response phase hook.
+
+ .. rb:attr_reader:: phase
+
+ Return the current phase.
+
+ .. rb:attr_reader:: remote_addr
+
+ Return IP address of a remote client. If connection is made
+ via UNIX domain socket, this returns the string "localhost".
+
+ .. rb:attr_reader:: server_addr
+
+ Return address of server that accepted the connection. This
+ is a string which specified in :option:`--frontend` option,
+ excluding port number, and not a resolved IP address. For
+ UNIX domain socket, this is a path to UNIX domain socket.
+
+ .. rb:attr_reader:: server_port
+
+ Return port number of the server frontend which accepted the
+ connection from client.
+
+ .. rb:attr_reader:: tls_used
+
+ Return true if TLS is used on the connection.
+
+ .. rb:attr_reader:: tls_sni
+
+ Return the TLS SNI value which client sent in this connection.
+
+ .. rb:attr_reader:: tls_client_fingerprint_sha256
+
+ Return the SHA-256 fingerprint of a client certificate.
+
+ .. rb:attr_reader:: tls_client_fingerprint_sha1
+
+ Return the SHA-1 fingerprint of a client certificate.
+
+ .. rb:attr_reader:: tls_client_issuer_name
+
+ Return the issuer name of a client certificate.
+
+ .. rb:attr_reader:: tls_client_subject_name
+
+ Return the subject name of a client certificate.
+
+ .. rb:attr_reader:: tls_client_serial
+
+ Return the serial number of a client certificate.
+
+ .. rb:attr_reader:: tls_client_not_before
+
+ Return the start date of a client certificate in seconds since
+ the epoch.
+
+ .. rb:attr_reader:: tls_client_not_after
+
+ Return the end date of a client certificate in seconds since
+ the epoch.
+
+ .. rb:attr_reader:: tls_cipher
+
+ Return a TLS cipher negotiated in this connection.
+
+ .. rb:attr_reader:: tls_protocol
+
+ Return a TLS protocol version negotiated in this connection.
+
+ .. rb:attr_reader:: tls_session_id
+
+ Return a session ID for this connection in hex string.
+
+ .. rb:attr_reader:: tls_session_reused
+
+ Return true if, and only if a SSL/TLS session is reused.
+
+ .. rb:attr_reader:: alpn
+
+ Return ALPN identifier negotiated in this connection.
+
+ .. rb:attr_reader:: tls_handshake_finished
+
+ Return true if SSL/TLS handshake has finished. If it returns
+ false in the request phase hook, the request is received in
+ TLSv1.3 early data (0-RTT) and might be vulnerable to the
+ replay attack. nghttpx will send Early-Data header field to
+ backend servers to indicate this.
+
+.. rb:class:: Request
+
+ Object to represent request from client. The modification to
+ Request object is allowed only in request phase hook.
+
+ .. rb:attr_reader:: http_version_major
+
+ Return HTTP major version.
+
+ .. rb:attr_reader:: http_version_minor
+
+ Return HTTP minor version.
+
+ .. rb:attr_accessor:: method
+
+ HTTP method. On assignment, copy of given value is assigned.
+ We don't accept arbitrary method name. We will document them
+ later, but well known methods, like GET, PUT and POST, are all
+ supported.
+
+ .. rb:attr_accessor:: authority
+
+ Authority (i.e., example.org), including optional port
+ component . On assignment, copy of given value is assigned.
+
+ .. rb:attr_accessor:: scheme
+
+ Scheme (i.e., http, https). On assignment, copy of given
+ value is assigned.
+
+ .. rb:attr_accessor:: path
+
+ Request path, including query component (i.e., /index.html).
+ On assignment, copy of given value is assigned. The path does
+ not include authority component of URI. This may include
+ query component. nghttpx makes certain normalization for
+ path. It decodes percent-encoding for unreserved characters
+ (see https://tools.ietf.org/html/rfc3986#section-2.3), and
+ resolves ".." and ".". But it may leave characters which
+ should be percent-encoded as is. So be careful when comparing
+ path against desired string.
+
+ .. rb:attr_reader:: headers
+
+ Return Ruby hash containing copy of request header fields.
+ Changing values in returned hash does not change request
+ header fields actually used in request processing. Use
+ :rb:meth:`Nghttpx::Request#add_header` or
+ :rb:meth:`Nghttpx::Request#set_header` to change request
+ header fields.
+
+ .. rb:method:: add_header(key, value)
+
+ Add header entry associated with key. The value can be single
+ string or array of string. It does not replace any existing
+ values associated with key.
+
+ .. rb:method:: set_header(key, value)
+
+ Set header entry associated with key. The value can be single
+ string or array of string. It replaces any existing values
+ associated with key.
+
+ .. rb:method:: clear_headers
+
+ Clear all existing request header fields.
+
+ .. rb:method:: push(uri)
+
+ Initiate to push resource identified by *uri*. Only HTTP/2
+ protocol supports this feature. For the other protocols, this
+ method is noop. *uri* can be absolute URI, absolute path or
+ relative path to the current request. For absolute or
+ relative path, scheme and authority are inherited from the
+ current request. Currently, method is always GET. nghttpx
+ will issue request to backend servers to fulfill this request.
+ The request and response phase hooks will be called for pushed
+ resource as well.
+
+.. rb:class:: Response
+
+ Object to represent response from backend server.
+
+ .. rb:attr_reader:: http_version_major
+
+ Return HTTP major version.
+
+ .. rb:attr_reader:: http_version_minor
+
+ Return HTTP minor version.
+
+ .. rb:attr_accessor:: status
+
+ HTTP status code. It must be in the range [200, 999],
+ inclusive. The non-final status code is not supported in
+ mruby scripting at the moment.
+
+ .. rb:attr_reader:: headers
+
+ Return Ruby hash containing copy of response header fields.
+ Changing values in returned hash does not change response
+ header fields actually used in response processing. Use
+ :rb:meth:`Nghttpx::Response#add_header` or
+ :rb:meth:`Nghttpx::Response#set_header` to change response
+ header fields.
+
+ .. rb:method:: add_header(key, value)
+
+ Add header entry associated with key. The value can be single
+ string or array of string. It does not replace any existing
+ values associated with key.
+
+ .. rb:method:: set_header(key, value)
+
+ Set header entry associated with key. The value can be single
+ string or array of string. It replaces any existing values
+ associated with key.
+
+ .. rb:method:: clear_headers
+
+ Clear all existing response header fields.
+
+ .. rb:method:: return(body)
+
+ Return custom response *body* to a client. When this method
+ is called in request phase hook, the request is not forwarded
+ to the backend, and response phase hook for this request will
+ not be invoked. When this method is called in response phase
+ hook, response from backend server is canceled and discarded.
+ The status code and response header fields should be set
+ before using this method. To set status code, use
+ :rb:attr:`Nghttpx::Response#status`. If status code is not
+ set, 200 is used. To set response header fields,
+ :rb:meth:`Nghttpx::Response#add_header` and
+ :rb:meth:`Nghttpx::Response#set_header`. When this method is
+ invoked in response phase hook, the response headers are
+ filled with the ones received from backend server. To send
+ completely custom header fields, first call
+ :rb:meth:`Nghttpx::Response#clear_headers` to erase all
+ existing header fields, and then add required header fields.
+ It is an error to call this method twice for a given request.
+
+ .. rb:method:: send_info(status, headers)
+
+ Send non-final (informational) response to a client. *status*
+ must be in the range [100, 199], inclusive. *headers* is a
+ hash containing response header fields. Its key must be a
+ string, and the associated value must be either string or
+ array of strings. Since this is not a final response, even if
+ this method is invoked, request is still forwarded to a
+ backend unless :rb:meth:`Nghttpx::Response#return` is called.
+ This method can be called multiple times. It cannot be called
+ after :rb:meth:`Nghttpx::Response#return` is called.
+
+MRUBY EXAMPLES
+~~~~~~~~~~~~~~
+
+Modify request path:
+
+.. code-block:: ruby
+
+ class App
+ def on_req(env)
+ env.req.path = "/apps#{env.req.path}"
+ end
+ end
+
+ App.new
+
+Don't forget to instantiate and evaluate object at the last line.
+
+Restrict permission of viewing a content to a specific client
+addresses:
+
+.. code-block:: ruby
+
+ class App
+ def on_req(env)
+ allowed_clients = ["127.0.0.1", "::1"]
+
+ if env.req.path.start_with?("/log/") &&
+ !allowed_clients.include?(env.remote_addr) then
+ env.resp.status = 404
+ env.resp.return "permission denied"
+ end
+ end
+ end
+
+ App.new
+
+API ENDPOINTS
+-------------
+
+nghttpx exposes API endpoints to manipulate it via HTTP based API. By
+default, API endpoint is disabled. To enable it, add a dedicated
+frontend for API using :option:`--frontend` option with "api"
+parameter. All requests which come from this frontend address, will
+be treated as API request.
+
+The response is normally JSON dictionary, and at least includes the
+following keys:
+
+status
+ The status of the request processing. The following values are
+ defined:
+
+ Success
+ The request was successful.
+
+ Failure
+ The request was failed. No change has been made.
+
+code
+ HTTP status code
+
+Additionally, depending on the API endpoint, ``data`` key may be
+present, and its value contains the API endpoint specific data.
+
+We wrote "normally", since nghttpx may return ordinal HTML response in
+some cases where the error has occurred before reaching API endpoint
+(e.g., header field is too large).
+
+The following section describes available API endpoints.
+
+POST /api/v1beta1/backendconfig
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This API replaces the current backend server settings with the
+requested ones. The request method should be POST, but PUT is also
+acceptable. The request body must be nghttpx configuration file
+format. For configuration file format, see `FILES`_ section. The
+line separator inside the request body must be single LF (0x0A).
+Currently, only :option:`backend <--backend>` option is parsed, the
+others are simply ignored. The semantics of this API is replace the
+current backend with the backend options in request body. Describe
+the desired set of backend severs, and nghttpx makes it happen. If
+there is no :option:`backend <--backend>` option is found in request
+body, the current set of backend is replaced with the :option:`backend
+<--backend>` option's default value, which is ``127.0.0.1,80``.
+
+The replacement is done instantly without breaking existing
+connections or requests. It also avoids any process creation as is
+the case with hot swapping with signals.
+
+The one limitation is that only numeric IP address is allowed in
+:option:`backend <--backend>` in request body unless "dns" parameter
+is used while non numeric hostname is allowed in command-line or
+configuration file is read using :option:`--conf`.
+
+GET /api/v1beta1/configrevision
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This API returns configuration revision of the current nghttpx. The
+configuration revision is opaque string, and it changes after each
+reloading by SIGHUP. With this API, an external application knows
+that whether nghttpx has finished reloading its configuration by
+comparing the configuration revisions between before and after
+reloading. It is recommended to disable persistent (keep-alive)
+connection for this purpose in order to avoid to send a request using
+the reused connection which may bound to an old process.
+
+This API returns response including ``data`` key. Its value is JSON
+object, and it contains at least the following key:
+
+configRevision
+ The configuration revision of the current nghttpx
+
+
+SEE ALSO
+--------
+
+:manpage:`nghttp(1)`, :manpage:`nghttpd(1)`, :manpage:`h2load(1)`
diff --git a/doc/package_README.rst.in b/doc/package_README.rst.in
new file mode 100644
index 0000000..dfa6b2d
--- /dev/null
+++ b/doc/package_README.rst.in
@@ -0,0 +1 @@
+.. include:: @top_srcdir@/README.rst
diff --git a/doc/programmers-guide.rst b/doc/programmers-guide.rst
new file mode 100644
index 0000000..820cd20
--- /dev/null
+++ b/doc/programmers-guide.rst
@@ -0,0 +1,526 @@
+Programmers' Guide
+==================
+
+Architecture
+------------
+
+The most notable point in nghttp2 library architecture is it does not
+perform any I/O. nghttp2 only performs HTTP/2 protocol stuff based on
+input byte strings. It will call callback functions set by
+applications while processing input. The output of nghttp2 is just
+byte string. An application is responsible to send these output to
+the remote peer. The callback functions may be called while producing
+output.
+
+Not doing I/O makes embedding nghttp2 library in the existing code
+base very easy. Usually, the existing applications have its own I/O
+event loops. It is very hard to use nghttp2 in that situation if
+nghttp2 does its own I/O. It also makes light weight language wrapper
+for nghttp2 easy with the same reason. The down side is that an
+application author has to write more code to write complete
+application using nghttp2. This is especially true for simple "toy"
+application. For the real applications, however, this is not the
+case. This is because you probably want to support HTTP/1 which
+nghttp2 does not provide, and to do that, you will need to write your
+own HTTP/1 stack or use existing third-party library, and bind them
+together with nghttp2 and I/O event loop. In this point, not
+performing I/O in nghttp2 has more point than doing it.
+
+The primary object that an application uses is :type:`nghttp2_session`
+object, which is opaque struct and its details are hidden in order to
+ensure the upgrading its internal architecture without breaking the
+backward compatibility. An application can set callbacks to
+:type:`nghttp2_session` object through the dedicated object and
+functions, and it also interacts with it via many API function calls.
+
+An application can create as many :type:`nghttp2_session` object as it
+wants. But single :type:`nghttp2_session` object must be used by a
+single thread at the same time. This is not so hard to enforce since
+most event-based architecture applications use is single thread per
+core, and handling one connection I/O is done by single thread.
+
+To feed input to :type:`nghttp2_session` object, one can use
+`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` functions.
+They behave similarly, and the difference is that
+`nghttp2_session_recv()` will use :type:`nghttp2_read_callback` to get
+input. On the other hand, `nghttp2_session_mem_recv()` will take
+input as its parameter. If in doubt, use `nghttp2_session_mem_recv()`
+since it is simpler, and could be faster since it avoids calling
+callback function.
+
+To get output from :type:`nghttp2_session` object, one can use
+`nghttp2_session_send()` or `nghttp2_session_mem_send()`. The
+difference between them is that the former uses
+:type:`nghttp2_send_callback` to pass output to an application. On
+the other hand, the latter returns the output to the caller. If in
+doubt, use `nghttp2_session_mem_send()` since it is simpler. But
+`nghttp2_session_send()` might be easier to use if the output buffer
+an application has is fixed sized.
+
+In general, an application should call `nghttp2_session_mem_send()`
+when it gets input from underlying connection. Since there is great
+chance to get something pushed into transmission queue while the call
+of `nghttp2_session_mem_send()`, it is recommended to call
+`nghttp2_session_mem_recv()` after `nghttp2_session_mem_send()`.
+
+There is a question when we are safe to close HTTP/2 session without
+waiting for the closure of underlying connection. We offer 2 API
+calls for this: `nghttp2_session_want_read()` and
+`nghttp2_session_want_write()`. If they both return 0, application
+can destroy :type:`nghttp2_session`, and then close the underlying
+connection. But make sure that the buffered output has been
+transmitted to the peer before closing the connection when
+`nghttp2_session_mem_send()` is used, since
+`nghttp2_session_want_write()` does not take into account the
+transmission of the buffered data outside of :type:`nghttp2_session`.
+
+Includes
+--------
+
+To use the public APIs, include ``nghttp2/nghttp2.h``::
+
+ #include <nghttp2/nghttp2.h>
+
+The header files are also available online: :doc:`nghttp2.h` and
+:doc:`nghttp2ver.h`.
+
+Remarks
+-------
+
+Do not call `nghttp2_session_send()`, `nghttp2_session_mem_send()`,
+`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` from the
+nghttp2 callback functions directly or indirectly. It will lead to the
+crash. You can submit requests or frames in the callbacks then call
+these functions outside the callbacks.
+
+`nghttp2_session_send()` and `nghttp2_session_mem_send()` send first
+24 bytes of client magic string (MAGIC)
+(:macro:`NGHTTP2_CLIENT_MAGIC`) on client configuration. The
+applications are responsible to send SETTINGS frame as part of
+connection preface using `nghttp2_submit_settings()`. Similarly,
+`nghttp2_session_recv()` and `nghttp2_session_mem_recv()` consume
+MAGIC on server configuration unless
+`nghttp2_option_set_no_recv_client_magic()` is used with nonzero
+option value.
+
+.. _http-messaging:
+
+HTTP Messaging
+--------------
+
+By default, nghttp2 library checks HTTP messaging rules described in
+`HTTP/2 specification, section 8
+<https://tools.ietf.org/html/rfc7540#section-8>`_. Everything
+described in that section is not validated however. We briefly
+describe what the library does in this area. In the following
+description, without loss of generality we omit CONTINUATION frame
+since they must follow HEADERS frame and are processed atomically. In
+other words, they are just one big HEADERS frame. To disable these
+validations, use `nghttp2_option_set_no_http_messaging()`. Please
+note that disabling this feature does not change the fundamental
+client and server model of HTTP. That is, even if the validation is
+disabled, only client can send requests.
+
+For HTTP request, including those carried by PUSH_PROMISE, HTTP
+message starts with one HEADERS frame containing request headers. It
+is followed by zero or more DATA frames containing request body, which
+is followed by zero or one HEADERS containing trailer headers. The
+request headers must include ":scheme", ":method" and ":path" pseudo
+header fields unless ":method" is not "CONNECT". ":authority" is
+optional, but nghttp2 requires either ":authority" or "Host" header
+field must be present. If ":method" is "CONNECT", the request headers
+must include ":method" and ":authority" and must omit ":scheme" and
+":path".
+
+For HTTP response, HTTP message starts with zero or more HEADERS
+frames containing non-final response (status code 1xx). They are
+followed by one HEADERS frame containing final response headers
+(non-1xx). It is followed by zero or more DATA frames containing
+response body, which is followed by zero or one HEADERS containing
+trailer headers. The non-final and final response headers must
+contain ":status" pseudo header field containing 3 digits only.
+
+All request and response headers must include exactly one valid value
+for each pseudo header field. Additionally nghttp2 requires all
+request headers must not include more than one "Host" header field.
+
+HTTP/2 prohibits connection-specific header fields. The following
+header fields must not appear: "Connection", "Keep-Alive",
+"Proxy-Connection", "Transfer-Encoding" and "Upgrade". Additionally,
+"TE" header field must not include any value other than "trailers".
+
+Each header field name and value must obey the field-name and
+field-value production rules described in `RFC 7230, section
+3.2. <https://tools.ietf.org/html/rfc7230#section-3.2>`_.
+Additionally, all field name must be lower cased. The invalid header
+fields are treated as stream error, and that stream is reset. If
+application wants to treat these headers in their own way, use
+`nghttp2_on_invalid_header_callback
+<https://nghttp2.org/documentation/types.html#c.nghttp2_on_invalid_header_callback>`_.
+
+For "http" or "https" URIs, ":path" pseudo header fields must start
+with "/". The only exception is OPTIONS request, in that case, "*" is
+allowed in ":path" pseudo header field to represent system-wide
+OPTIONS request.
+
+With the above validations, nghttp2 library guarantees that header
+field name passed to `nghttp2_on_header_callback()` is not empty.
+Also required pseudo headers are all present and not empty.
+
+nghttp2 enforces "Content-Length" validation as well. All request or
+response headers must not contain more than one "Content-Length"
+header field. If "Content-Length" header field is present, it must be
+parsed as 64 bit signed integer. The sum of data length in the
+following DATA frames must match with the number in "Content-Length"
+header field if it is present (this does not include padding bytes).
+
+RFC 7230 says that server must not send "Content-Length" in any
+response with 1xx, and 204 status code. It also says that
+"Content-Length" is not allowed in any response with 200 status code
+to a CONNECT request. nghttp2 enforces them as well.
+
+Any deviation results in stream error of type PROTOCOL_ERROR. If
+error is found in PUSH_PROMISE frame, stream error is raised against
+promised stream.
+
+The order of transmission of the HTTP/2 frames
+----------------------------------------------
+
+This section describes the internals of libnghttp2 about the
+scheduling of transmission of HTTP/2 frames. This is pretty much
+internal stuff, so the details could change in the future versions of
+the library.
+
+libnghttp2 categorizes HTTP/2 frames into 4 categories: urgent,
+regular, syn_stream, and data in the order of higher priority.
+
+The urgent category includes PING and SETTINGS. They are sent with
+highest priority. The order inside the category is FIFO.
+
+The regular category includes frames other than PING, SETTINGS, DATA,
+and HEADERS which does not create stream (which counts toward
+concurrent stream limit). The order inside the category is FIFO.
+
+The syn_stream category includes HEADERS frame which creates stream,
+that counts toward the concurrent stream limit.
+
+The data category includes DATA frame, and the scheduling among DATA
+frames are determined by HTTP/2 dependency tree.
+
+If the application wants to send frames in the specific order, and the
+default transmission order does not fit, it has to schedule frames by
+itself using the callbacks (e.g.,
+:type:`nghttp2_on_frame_send_callback`).
+
+RST_STREAM has special side effect when it is submitted by
+`nghttp2_submit_rst_stream()`. It cancels all pending HEADERS and
+DATA frames whose stream ID matches the one in the RST_STREAM frame.
+This may cause unexpected behaviour for the application in some cases.
+For example, suppose that application wants to send RST_STREAM after
+sending response HEADERS and DATA. Because of the reason we mentioned
+above, the following code does not work:
+
+.. code-block:: c
+
+ nghttp2_submit_response(...)
+ nghttp2_submit_rst_stream(...)
+
+RST_STREAM cancels HEADERS (and DATA), and just RST_STREAM is sent.
+The correct way is use :type:`nghttp2_on_frame_send_callback`, and
+after HEADERS and DATA frames are sent, issue
+`nghttp2_submit_rst_stream()`. FYI,
+:type:`nghttp2_on_frame_not_send_callback` tells you why frames are
+not sent.
+
+Implement user defined HTTP/2 non-critical extensions
+-----------------------------------------------------
+
+As of nghttp2 v1.8.0, we have added HTTP/2 non-critical extension
+framework, which lets application send and receive user defined custom
+HTTP/2 non-critical extension frames. nghttp2 also offers built-in
+functionality to send and receive official HTTP/2 extension frames
+(e.g., ALTSVC frame). For these built-in handler, refer to the next
+section.
+
+To send extension frame, use `nghttp2_submit_extension()`, and
+implement :type:`nghttp2_pack_extension_callback`. The callback
+implements how to encode data into wire format. The callback must be
+set to :type:`nghttp2_session_callbacks` using
+`nghttp2_session_callbacks_set_pack_extension_callback()`.
+
+For example, we will illustrate how to send `ALTSVC
+<https://tools.ietf.org/html/rfc7838>`_ frame.
+
+.. code-block:: c
+
+ typedef struct {
+ const char *origin;
+ const char *field;
+ } alt_svc;
+
+ ssize_t pack_extension_callback(nghttp2_session *session, uint8_t *buf,
+ size_t len, const nghttp2_frame *frame,
+ void *user_data) {
+ const alt_svc *altsvc = (const alt_svc *)frame->ext.payload;
+ size_t originlen = strlen(altsvc->origin);
+ size_t fieldlen = strlen(altsvc->field);
+
+ uint8_t *p;
+
+ if (len < 2 + originlen + fieldlen || originlen > 0xffff) {
+ return NGHTTP2_ERR_CANCEL;
+ }
+
+ p = buf;
+ *p++ = originlen >> 8;
+ *p++ = originlen & 0xff;
+ memcpy(p, altsvc->origin, originlen);
+ p += originlen;
+ memcpy(p, altsvc->field, fieldlen);
+ p += fieldlen;
+
+ return p - buf;
+ }
+
+This implements :type:`nghttp2_pack_extension_callback`. We have to
+set this callback to :type:`nghttp2_session_callbacks`:
+
+.. code-block:: c
+
+ nghttp2_session_callbacks_set_pack_extension_callback(
+ callbacks, pack_extension_callback);
+
+To send ALTSVC frame, call `nghttp2_submit_extension()`:
+
+.. code-block:: c
+
+ static const alt_svc altsvc = {"example.com", "h2=\":8000\""};
+
+ nghttp2_submit_extension(session, 0xa, NGHTTP2_FLAG_NONE, 0,
+ (void *)&altsvc);
+
+Notice that ALTSVC is use frame type ``0xa``.
+
+To receive extension frames, implement 2 callbacks:
+:type:`nghttp2_unpack_extension_callback` and
+:type:`nghttp2_on_extension_chunk_recv_callback`.
+:type:`nghttp2_unpack_extension_callback` implements the way how to
+decode wire format. :type:`nghttp2_on_extension_chunk_recv_callback`
+implements how to buffer the incoming extension payload. These
+callbacks must be set using
+`nghttp2_session_callbacks_set_unpack_extension_callback()` and
+`nghttp2_session_callbacks_set_on_extension_chunk_recv_callback()`
+respectively. The application also must tell the library which
+extension frame type it is willing to receive using
+`nghttp2_option_set_user_recv_extension_type()`. Note that the
+application has to create :type:`nghttp2_option` object for that
+purpose, and initialize session with it.
+
+We use ALTSVC again to illustrate how to receive extension frames. We
+use different ``alt_svc`` struct than the previous one.
+
+First implement 2 callbacks. We store incoming ALTSVC payload to
+global variable ``altsvc_buffer``. Don't do this in production code
+since this is not thread safe:
+
+.. code-block:: c
+
+ typedef struct {
+ const uint8_t *origin;
+ size_t originlen;
+ const uint8_t *field;
+ size_t fieldlen;
+ } alt_svc;
+
+ /* buffers incoming ALTSVC payload */
+ uint8_t altsvc_buffer[4096];
+ /* The length of byte written to altsvc_buffer */
+ size_t altsvc_bufferlen = 0;
+
+ int on_extension_chunk_recv_callback(nghttp2_session *session,
+ const nghttp2_frame_hd *hd,
+ const uint8_t *data, size_t len,
+ void *user_data) {
+ if (sizeof(altsvc_buffer) < altsvc_bufferlen + len) {
+ altsvc_bufferlen = 0;
+ return NGHTTP2_ERR_CANCEL;
+ }
+
+ memcpy(altsvc_buffer + altsvc_bufferlen, data, len);
+ altsvc_bufferlen += len;
+
+ return 0;
+ }
+
+ int unpack_extension_callback(nghttp2_session *session, void **payload,
+ const nghttp2_frame_hd *hd, void *user_data) {
+ uint8_t *origin, *field;
+ size_t originlen, fieldlen;
+ uint8_t *p, *end;
+ alt_svc *altsvc;
+
+ if (altsvc_bufferlen < 2) {
+ altsvc_bufferlen = 0;
+ return NGHTTP2_ERR_CANCEL;
+ }
+
+ p = altsvc_buffer;
+ end = altsvc_buffer + altsvc_bufferlen;
+
+ originlen = ((*p) << 8) + *(p + 1);
+ p += 2;
+
+ if (p + originlen > end) {
+ altsvc_bufferlen = 0;
+ return NGHTTP2_ERR_CANCEL;
+ }
+
+ origin = p;
+ field = p + originlen;
+ fieldlen = end - field;
+
+ altsvc = (alt_svc *)malloc(sizeof(alt_svc));
+ altsvc->origin = origin;
+ altsvc->originlen = originlen;
+ altsvc->field = field;
+ altsvc->fieldlen = fieldlen;
+
+ *payload = altsvc;
+
+ altsvc_bufferlen = 0;
+
+ return 0;
+ }
+
+Set these callbacks to :type:`nghttp2_session_callbacks`:
+
+.. code-block:: c
+
+ nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
+ callbacks, on_extension_chunk_recv_callback);
+
+ nghttp2_session_callbacks_set_unpack_extension_callback(
+ callbacks, unpack_extension_callback);
+
+
+In ``unpack_extension_callback`` above, we set unpacked ``alt_svc``
+object to ``*payload``. nghttp2 library then, calls
+:type:`nghttp2_on_frame_recv_callback`, and ``*payload`` will be
+available as ``frame->ext.payload``:
+
+.. code-block:: c
+
+ int on_frame_recv_callback(nghttp2_session *session,
+ const nghttp2_frame *frame, void *user_data) {
+
+ switch (frame->hd.type) {
+ ...
+ case 0xa: {
+ alt_svc *altsvc = (alt_svc *)frame->ext.payload;
+ fprintf(stderr, "ALTSVC frame received\n");
+ fprintf(stderr, " origin: %.*s\n", (int)altsvc->originlen, altsvc->origin);
+ fprintf(stderr, " field : %.*s\n", (int)altsvc->fieldlen, altsvc->field);
+ free(altsvc);
+ break;
+ }
+ }
+
+ return 0;
+ }
+
+Finally, application should set the extension frame types it is
+willing to receive:
+
+.. code-block:: c
+
+ nghttp2_option_set_user_recv_extension_type(option, 0xa);
+
+The :type:`nghttp2_option` must be set to :type:`nghttp2_session` on
+its creation:
+
+.. code-block:: c
+
+ nghttp2_session_client_new2(&session, callbacks, user_data, option);
+
+How to use built-in HTTP/2 extension frame handlers
+---------------------------------------------------
+
+In the previous section, we talked about the user defined HTTP/2
+extension frames. In this section, we talk about HTTP/2 extension
+frame support built into nghttp2 library.
+
+As of this writing, nghttp2 supports ALTSVC extension frame. To send
+ALTSVC frame, use `nghttp2_submit_altsvc()` function.
+
+To receive ALTSVC frame through built-in functionality, application
+has to use `nghttp2_option_set_builtin_recv_extension_type()` to
+indicate the willingness of receiving ALTSVC frame:
+
+.. code-block:: c
+
+ nghttp2_option_set_builtin_recv_extension_type(option, NGHTTP2_ALTSVC);
+
+This is very similar to the case when we used to receive user defined
+frames.
+
+If the same frame type is set using
+`nghttp2_option_set_builtin_recv_extension_type()` and
+`nghttp2_option_set_user_recv_extension_type()`, the latter takes
+precedence. Application can implement its own frame handler rather
+than using built-in handler.
+
+The :type:`nghttp2_option` must be set to :type:`nghttp2_session` on
+its creation, like so:
+
+.. code-block:: c
+
+ nghttp2_session_client_new2(&session, callbacks, user_data, option);
+
+When ALTSVC is received, :type:`nghttp2_on_frame_recv_callback` will
+be called as usual.
+
+Stream priorities
+-----------------
+
+By default, the stream prioritization scheme described in :rfc:`7540`
+is used. This scheme has been formally deprecated by :rfc:`9113`. In
+order to disable it, send
+:enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` of
+value of 1 via `nghttp2_submit_settings()`. This settings ID is
+defined by :rfc:`9218`. The sender of this settings value disables
+RFC 7540 priorities, and instead it enables RFC 9218 Extensible
+Prioritization Scheme. This new prioritization scheme has 2 methods
+to convey the stream priorities to a remote endpoint: Priority header
+field and PRIORITY_UPDATE frame. nghttp2 supports both methods. In
+order to receive and process PRIORITY_UPDATE frame, server has to call
+``nghttp2_option_set_builtin_recv_extension_type(option,
+NGHTTP2_PRIORITY_UPDATE)`` (see the above section), and pass the
+option to `nghttp2_session_server_new2()` or
+`nghttp2_session_server_new3()` to create a server session. Client
+can send Priority header field via `nghttp2_submit_request()`. It can
+also send PRIORITY_UPDATE frame via
+`nghttp2_submit_priority_update()`. Server processes Priority header
+field in a request header field and updates the stream priority unless
+HTTP messaging rule enforcement is disabled (see
+`nghttp2_option_set_no_http_messaging()`).
+
+For the purpose of smooth migration from RFC 7540 priorities, client
+is advised to send
+:enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` of
+value of 1. Until it receives the first server SETTINGS frame, it can
+send both RFC 7540 and RFC 9128 priority signals. If client receives
+SETTINGS_NO_RFC7540_PRIORITIES of value of 0, or it is omitted ,
+client stops sending PRIORITY_UPDATE frame. Priority header field
+will be sent in anyway since it is an end-to-end signal. If
+SETTINGS_NO_RFC7540_PRIORITIES of value of 1 is received, client stops
+sending RFC 7540 priority signals. This is the advice described in
+:rfc:`9218#section-2.1.1`.
+
+Server has an optional mechanism to fallback to RFC 7540 priorities.
+By default, if server sends SETTINGS_NO_RFC7540_PRIORITIES of value of
+1, it completely disables RFC 7540 priorities and no fallback. By
+setting nonzero value to
+`nghttp2_option_set_server_fallback_rfc7540_priorities()`, server
+falls back to RFC 7540 priorities if it sends
+SETTINGS_NO_RFC7540_PRIORITIES value of value of 1, and client omits
+SETTINGS_NO_RFC7540_PRIORITIES in its SETTINGS frame.
diff --git a/doc/security.rst b/doc/security.rst
new file mode 100644
index 0000000..00b0c9c
--- /dev/null
+++ b/doc/security.rst
@@ -0,0 +1 @@
+.. include:: ../doc/sources/security.rst
diff --git a/doc/sources/building-android-binary.rst b/doc/sources/building-android-binary.rst
new file mode 100644
index 0000000..339ac44
--- /dev/null
+++ b/doc/sources/building-android-binary.rst
@@ -0,0 +1,127 @@
+Building Android binary
+=======================
+
+In this article, we briefly describe how to build Android binary using
+`Android NDK <https://developer.android.com/ndk>`_ cross-compiler on
+Debian Linux.
+
+The easiest way to build android binary is use Dockerfile.android.
+See Dockerfile.android for more details. If you cannot use
+Dockerfile.android for whatever reason, continue to read the rest of
+this article.
+
+We offer ``android-config`` script to make the build easier. To make
+the script work, NDK directory must be set to ``NDK`` environment
+variable. NDK directory is the directory where NDK is unpacked:
+
+.. code-block:: text
+
+ $ unzip android-ndk-$NDK_VERSION-linux.zip
+ $ cd android-ndk-$NDK_VERSION
+ $ export NDK=$PWD
+
+The dependent libraries, such as OpenSSL, libev, and c-ares should be
+built with the same NDK toolchain and installed under
+``$NDK/usr/local``. We recommend to build these libraries as static
+library to make the deployment easier. libxml2 support is currently
+disabled.
+
+Although zlib comes with Android NDK, it seems not to be a part of
+public API, so we have to built it for our own. That also provides us
+proper .pc file as a bonus.
+
+Before running ``android-config``, ``NDK`` environment variable must
+be set to point to the correct path.
+
+You need to set ``NGHTTP2`` environment variable to the absolute path
+to the source directory of nghttp2.
+
+To configure OpenSSL, use the following script:
+
+.. code-block:: sh
+
+ #!/bin/sh
+
+ . $NGHTTP2/android-env
+
+ export ANDROID_NDK_HOME=$NDK
+ export PATH=$TOOLCHAIN/bin:$PATH
+
+ ./Configure no-shared --prefix=$PREFIX android-arm64
+
+And run the following script to build and install without
+documentation:
+
+.. code-block:: sh
+
+ #!/bin/sh
+
+ . $NGHTTP2/android-env
+
+ export PATH=$TOOLCHAIN/bin:$PATH
+
+ make install_sw
+
+To configure libev, use the following script:
+
+.. code-block:: sh
+
+ #!/bin/sh
+
+ . $NGHTTP2/android-env
+
+ ./configure \
+ --host=$TARGET \
+ --build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
+ --prefix=$PREFIX \
+ --disable-shared \
+ --enable-static \
+ CPPFLAGS=-I$PREFIX/include \
+ LDFLAGS=-L$PREFIX/lib
+
+And run ``make install`` to build and install.
+
+To configure c-ares, use the following script:
+
+.. code-block:: sh
+
+ #!/bin/sh -e
+
+ . $NGHTTP2/android-env
+
+ ./configure \
+ --host=$TARGET \
+ --build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
+ --prefix=$PREFIX \
+ --disable-shared
+
+And run ``make install`` to build and install.
+
+To configure zlib, use the following script:
+
+.. code-block:: sh
+
+ #!/bin/sh -e
+
+ . $NGHTTP2/android-env
+
+ export HOST=$TARGET
+
+ ./configure \
+ --prefix=$PREFIX \
+ --libdir=$PREFIX/lib \
+ --includedir=$PREFIX/include \
+ --static
+
+And run ``make install`` to build and install.
+
+After prerequisite libraries are prepared, run ``android-config`` and
+then ``make`` to compile nghttp2 source files.
+
+If all went well, application binaries, such as nghttpx, are created
+under src directory. Strip debugging information from the binary
+using the following command:
+
+.. code-block:: text
+
+ $ $NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip src/nghttpx
diff --git a/doc/sources/contribute.rst b/doc/sources/contribute.rst
new file mode 100644
index 0000000..1e39f2b
--- /dev/null
+++ b/doc/sources/contribute.rst
@@ -0,0 +1,56 @@
+Contribution Guidelines
+=======================
+
+[This text was composed based on 1.2. License section of curl/libcurl
+project.]
+
+When contributing with code, you agree to put your changes and new
+code under the same license nghttp2 is already using unless stated and
+agreed otherwise.
+
+When changing existing source code, you do not alter the copyright of
+the original file(s). The copyright will still be owned by the
+original creator(s) or those who have been assigned copyright by the
+original author(s).
+
+By submitting a patch to the nghttp2 project, you are assumed to have
+the right to the code and to be allowed by your employer or whatever
+to hand over that patch/code to us. We will credit you for your
+changes as far as possible, to give credit but also to keep a trace
+back to who made what changes. Please always provide us with your
+full real name when contributing!
+
+Coding style
+------------
+
+We use clang-format to format source code consistently. The
+clang-format configuration file .clang-format is located at the root
+directory. Since clang-format produces slightly different results
+between versions, we currently use clang-format-15.
+
+To detect any violation to the coding style, we recommend to setup git
+pre-commit hook to check coding style of the changes you introduced.
+The pre-commit file is located at the root directory. Copy it under
+.git/hooks and make sure that it is executable. The pre-commit script
+uses clang-format-diff.py to detect any style errors. If it is not in
+your PATH or it exists under different name (e.g.,
+clang-format-diff-14 in debian), either add it to PATH variable or add
+git option ``clangformatdiff.binary`` to point to the script.
+
+For emacs users, integrating clang-format to emacs is very easy.
+clang-format.el should come with clang distribution. If it is not
+found, download it from `here
+<https://github.com/llvm/llvm-project/blob/main/clang/tools/clang-format/clang-format.el>`_.
+And add these lines to your .emacs file:
+
+.. code-block:: lisp
+
+ ;; From
+ ;; https://code.google.com/p/chromium/wiki/Emacs#Use_Google's_C++_style!
+ (load "/<path/to>/clang-format.el")
+ (add-hook 'c-mode-common-hook
+ (function (lambda () (local-set-key (kbd "TAB")
+ 'clang-format-region))))
+
+You can find other editor integration in
+http://clang.llvm.org/docs/ClangFormat.html.
diff --git a/doc/sources/h2load-howto.rst b/doc/sources/h2load-howto.rst
new file mode 100644
index 0000000..879a0eb
--- /dev/null
+++ b/doc/sources/h2load-howto.rst
@@ -0,0 +1,142 @@
+.. program:: h2load
+
+h2load - HTTP/2 benchmarking tool - HOW-TO
+==========================================
+
+:doc:`h2load.1` is benchmarking tool for HTTP/2 and HTTP/1.1. It
+supports SSL/TLS and clear text for all supported protocols.
+
+Compiling from source
+---------------------
+
+h2load is compiled alongside nghttp2 and requires that the
+``--enable-app`` flag is passed to ``./configure`` and `required
+dependencies <https://github.com/nghttp2/nghttp2#requirements>`_ are
+available during compilation. For details on compiling, see `nghttp2:
+Building from Git
+<https://github.com/nghttp2/nghttp2#building-from-git>`_.
+
+Basic Usage
+-----------
+
+In order to set benchmark settings, specify following 3 options.
+
+:option:`-n`
+ The number of total requests. Default: 1
+
+:option:`-c`
+ The number of concurrent clients. Default: 1
+
+:option:`-m`
+ The max concurrent streams to issue per client. Default: 1
+
+For SSL/TLS connection, the protocol will be negotiated via ALPN. You
+can set specific protocols in :option:`--alpn-list` option. For
+cleartext connection, the default protocol is HTTP/2. To change the
+protocol in cleartext connection, use :option:`--no-tls-proto` option.
+For convenience, :option:`--h1` option forces HTTP/1.1 for both
+cleartext and SSL/TLS connections.
+
+Here is a command-line to perform benchmark to URI \https://localhost
+using total 100000 requests, 100 concurrent clients and 10 max
+concurrent streams:
+
+.. code-block:: text
+
+ $ h2load -n100000 -c100 -m10 https://localhost
+
+The benchmarking result looks like this:
+
+.. code-block:: text
+
+ finished in 7.08s, 141164.80 req/s, 555.33MB/s
+ requests: 1000000 total, 1000000 started, 1000000 done, 1000000 succeeded, 0 failed, 0 errored, 0 timeout
+ status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx
+ traffic: 4125025824 bytes total, 11023424 bytes headers (space savings 93.07%), 4096000000 bytes data
+ min max mean sd +/- sd
+ time for request: 15.31ms 146.85ms 69.78ms 9.26ms 92.43%
+ time for connect: 1.08ms 25.04ms 10.71ms 9.80ms 64.00%
+ time to 1st byte: 25.36ms 184.96ms 79.11ms 53.97ms 78.00%
+ req/s (client) : 1412.04 1447.84 1426.52 10.57 63.00%
+
+See the h2load manual page :ref:`h2load-1-output` section for the
+explanation of the above numbers.
+
+Timing-based load-testing
+-------------------------
+
+As of v1.26.0, h2load supports timing-based load-testing. This method
+performs load-testing in terms of a given duration instead of a
+pre-defined number of requests. The new option :option:`--duration`
+specifies how long the load-testing takes. For example,
+``--duration=10`` makes h2load perform load-testing against a server
+for 10 seconds. You can also specify a “warming-up” period with
+:option:`--warm-up-time`. If :option:`--duration` is used,
+:option:`-n` option is ignored.
+
+The following command performs load-testing for 10 seconds after 5
+seconds warming up period:
+
+.. code-block:: text
+
+ $ h2load -c100 -m100 --duration=10 --warm-up-time=5 https://localhost
+
+Flow Control
+------------
+
+HTTP/2 has flow control and it may affect benchmarking results. By
+default, h2load uses large enough flow control window, which
+effectively disables flow control. To adjust receiver flow control
+window size, there are following options:
+
+:option:`-w`
+ Sets the stream level initial window size to
+ (2**<N>)-1.
+
+:option:`-W`
+ Sets the connection level initial window size to
+ (2**<N>)-1.
+
+Multi-Threading
+---------------
+
+Sometimes benchmarking client itself becomes a bottleneck. To remedy
+this situation, use :option:`-t` option to specify the number of native
+thread to use.
+
+:option:`-t`
+ The number of native threads. Default: 1
+
+Selecting protocol for clear text
+---------------------------------
+
+By default, if \http:// URI is given, HTTP/2 protocol is used. To
+change the protocol to use for clear text, use :option:`-p` option.
+
+Multiple URIs
+-------------
+
+If multiple URIs are specified, they are used in round robin manner.
+
+.. note::
+
+ Please note that h2load uses scheme, host and port in the first URI
+ and ignores those parts in the rest of the URIs.
+
+UNIX domain socket
+------------------
+
+To request against UNIX domain socket, use :option:`--base-uri`, and
+specify ``unix:`` followed by the path to UNIX domain socket. For
+example, if UNIX domain socket is ``/tmp/nghttpx.sock``, use
+``--base-uri=unix:/tmp/nghttpx.sock``. h2load uses scheme, host and
+port in the first URI in command-line or input file.
+
+HTTP/3
+------
+
+h2load supports HTTP/3 if it is built with HTTP/3 enabled. HTTP/3
+support is experimental.
+
+In order to send HTTP/3 request, specify ``h3`` to
+:option:`--alpn-list`.
diff --git a/doc/sources/index.rst b/doc/sources/index.rst
new file mode 100644
index 0000000..b03c348
--- /dev/null
+++ b/doc/sources/index.rst
@@ -0,0 +1,50 @@
+.. nghttp2 documentation main file, created by
+ sphinx-quickstart on Sun Mar 11 22:57:49 2012.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+nghttp2 - HTTP/2 C Library
+============================
+
+This is an implementation of Hypertext Transfer Protocol version 2.
+
+The project is hosted at `github.com/nghttp2/nghttp2
+<https://github.com/nghttp2/nghttp2>`_.
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ package_README
+ contribute
+ security
+ building-android-binary
+ tutorial-client
+ tutorial-server
+ tutorial-hpack
+ nghttp.1
+ nghttpd.1
+ nghttpx.1
+ h2load.1
+ nghttpx-howto
+ h2load-howto
+ programmers-guide
+ apiref
+ nghttp2.h
+ nghttp2ver.h
+ Source <https://github.com/nghttp2/nghttp2>
+ Issues <https://github.com/nghttp2/nghttp2/issues>
+ nghttp2.org <https://nghttp2.org/>
+
+Released Versions
+=================
+
+https://github.com/nghttp2/nghttp2/releases
+
+Resources
+---------
+
+* HTTP/2 https://tools.ietf.org/html/rfc7540
+* HPACK https://tools.ietf.org/html/rfc7541
+* HTTP Alternative Services https://tools.ietf.org/html/rfc7838
diff --git a/doc/sources/nghttpx-howto.rst b/doc/sources/nghttpx-howto.rst
new file mode 100644
index 0000000..50412f7
--- /dev/null
+++ b/doc/sources/nghttpx-howto.rst
@@ -0,0 +1,642 @@
+.. program:: nghttpx
+
+nghttpx - HTTP/2 proxy - HOW-TO
+===============================
+
+:doc:`nghttpx.1` is a proxy translating protocols between HTTP/2 and
+other protocols (e.g., HTTP/1). It operates in several modes and each
+mode may require additional programs to work with. This article
+describes each operation mode and explains the intended use-cases. It
+also covers some useful options later.
+
+Default mode
+------------
+
+If nghttpx is invoked without :option:`--http2-proxy`, it operates in
+default mode. In this mode, it works as reverse proxy (gateway) for
+HTTP/3, HTTP/2 and HTTP/1 clients to backend servers. This is also
+known as "HTTP/2 router".
+
+By default, frontend connection is encrypted using SSL/TLS. So
+server's private key and certificate must be supplied to the command
+line (or through configuration file). In this case, the frontend
+protocol selection will be done via ALPN.
+
+To turn off encryption on frontend connection, use ``no-tls`` keyword
+in :option:`--frontend` option. HTTP/2 and HTTP/1 are available on
+the frontend, and an HTTP/1 connection can be upgraded to HTTP/2 using
+HTTP Upgrade. Starting HTTP/2 connection by sending HTTP/2 connection
+preface is also supported.
+
+In order to receive HTTP/3 traffic, use ``quic`` parameter in
+:option:`--frontend` option (.e.g, ``--frontend='*,443;quic'``)
+
+nghttpx can listen on multiple frontend addresses. This is achieved
+by using multiple :option:`--frontend` options. For each frontend
+address, TLS can be enabled or disabled.
+
+By default, backend connections are not encrypted. To enable TLS
+encryption on backend connections, use ``tls`` keyword in
+:option:`--backend` option. Using patterns and ``proto`` keyword in
+:option:`--backend` option, backend application protocol can be
+specified per host/request path pattern. It means that you can use
+both HTTP/2 and HTTP/1 in backend connections at the same time. Note
+that default backend protocol is HTTP/1.1. To use HTTP/2 in backend,
+you have to specify ``h2`` in ``proto`` keyword in :option:`--backend`
+explicitly.
+
+The backend is supposed to be a Web server. For example, to make
+nghttpx listen to encrypted HTTP/2 requests at port 8443, and a
+backend Web server is configured to listen to HTTP requests at port
+8080 on the same host, run nghttpx command-line like this:
+
+.. code-block:: text
+
+ $ nghttpx -f0.0.0.0,8443 -b127.0.0.1,8080 /path/to/server.key /path/to/server.crt
+
+Then an HTTP/2 enabled client can access the nghttpx server using HTTP/2. For
+example, you can send a GET request using nghttp:
+
+.. code-block:: text
+
+ $ nghttp -nv https://localhost:8443/
+
+HTTP/2 proxy mode
+-----------------
+
+If nghttpx is invoked with :option:`--http2-proxy` (or its shorthand
+:option:`-s`) option, it operates in HTTP/2 proxy mode. The supported
+protocols in frontend and backend connections are the same as in `default
+mode`_. The difference is that this mode acts like a forward proxy and
+assumes the backend is an HTTP proxy server (e.g., Squid, Apache Traffic
+Server). HTTP/1 requests must include an absolute URI in request line.
+
+By default, the frontend connection is encrypted. So this mode is
+also called secure proxy.
+
+To turn off encryption on the frontend connection, use ``no-tls`` keyword
+in :option:`--frontend` option.
+
+The backend must be an HTTP proxy server. nghttpx supports multiple
+backend server addresses. It translates incoming requests to HTTP
+request to backend server. The backend server performs real proxy
+work for each request, for example, dispatching requests to the origin
+server and caching contents.
+
+The backend connection is not encrypted by default. To enable
+encryption, use ``tls`` keyword in :option:`--backend` option. The
+default backend protocol is HTTP/1.1. To use HTTP/2 in backend
+connection, use :option:`--backend` option, and specify ``h2`` in
+``proto`` keyword explicitly.
+
+For example, to make nghttpx listen to encrypted HTTP/2 requests at
+port 8443, and a backend HTTP proxy server is configured to listen to
+HTTP/1 requests at port 8080 on the same host, run nghttpx command-line
+like this:
+
+.. code-block:: text
+
+ $ nghttpx -s -f'*,8443' -b127.0.0.1,8080 /path/to/server.key /path/to/server.crt
+
+At the time of this writing, Firefox 41 and Chromium v46 can use
+nghttpx as HTTP/2 proxy.
+
+To make Firefox or Chromium use nghttpx as HTTP/2 proxy, user has to
+create proxy.pac script file like this:
+
+.. code-block:: javascript
+
+ function FindProxyForURL(url, host) {
+ return "HTTPS SERVERADDR:PORT";
+ }
+
+``SERVERADDR`` and ``PORT`` is the hostname/address and port of the
+machine nghttpx is running. Please note that both Firefox and
+Chromium require valid certificate for secure proxy.
+
+For Firefox, open Preference window and select Advanced then click
+Network tab. Clicking Connection Settings button will show the
+dialog. Select "Automatic proxy configuration URL" and enter the path
+to proxy.pac file, something like this:
+
+.. code-block:: text
+
+ file:///path/to/proxy.pac
+
+For Chromium, use following command-line:
+
+.. code-block:: text
+
+ $ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
+
+As HTTP/1 proxy server, Squid may work as out-of-box. Traffic server
+requires to be configured as forward proxy. Here is the minimum
+configuration items to edit:
+
+.. code-block:: text
+
+ CONFIG proxy.config.reverse_proxy.enabled INT 0
+ CONFIG proxy.config.url_remap.remap_required INT 0
+
+Consult Traffic server `documentation
+<http://trafficserver.readthedocs.org/en/latest/admin-guide/configuration/transparent-forward-proxying.en.html>`_
+to know how to configure traffic server as forward proxy and its
+security implications.
+
+ALPN support
+------------
+
+ALPN support requires OpenSSL >= 1.0.2.
+
+Disable frontend SSL/TLS
+------------------------
+
+The frontend connections are encrypted with SSL/TLS by default. To
+turn off SSL/TLS, use ``no-tls`` keyword in :option:`--frontend`
+option. If this option is used, the private key and certificate are
+not required to run nghttpx.
+
+Enable backend SSL/TLS
+----------------------
+
+The backend connections are not encrypted by default. To enable
+SSL/TLS encryption, use ``tls`` keyword in :option:`--backend` option.
+
+Enable SSL/TLS on memcached connection
+--------------------------------------
+
+By default, memcached connection is not encrypted. To enable
+encryption, use ``tls`` keyword in
+:option:`--tls-ticket-key-memcached` for TLS ticket key, and
+:option:`--tls-session-cache-memcached` for TLS session cache.
+
+Specifying additional server certificates
+-----------------------------------------
+
+nghttpx accepts additional server private key and certificate pairs
+using :option:`--subcert` option. It can be used multiple times.
+
+Specifying additional CA certificate
+------------------------------------
+
+By default, nghttpx tries to read CA certificate from system. But
+depending on the system you use, this may fail or is not supported.
+To specify CA certificate manually, use :option:`--cacert` option.
+The specified file must be PEM format and can contain multiple
+certificates.
+
+By default, nghttpx validates server's certificate. If you want to
+turn off this validation, knowing this is really insecure and what you
+are doing, you can use :option:`--insecure` option to disable
+certificate validation.
+
+Read/write rate limit
+---------------------
+
+nghttpx supports transfer rate limiting on frontend connections. You
+can do rate limit per frontend connection for reading and writing
+individually.
+
+To perform rate limit for reading, use :option:`--read-rate` and
+:option:`--read-burst` options. For writing, use
+:option:`--write-rate` and :option:`--write-burst`.
+
+Please note that rate limit is performed on top of TCP and nothing to
+do with HTTP/2 flow control.
+
+Rewriting location header field
+-------------------------------
+
+nghttpx automatically rewrites location response header field if the
+following all conditions satisfy:
+
+* In the default mode (:option:`--http2-proxy` is not used)
+* :option:`--no-location-rewrite` is not used
+* URI in location header field is an absolute URI
+* URI in location header field includes non empty host component.
+* host (without port) in URI in location header field must match the
+ host appearing in ``:authority`` or ``host`` header field.
+
+When rewrite happens, URI scheme is replaced with the ones used in
+frontend, and authority is replaced with which appears in
+``:authority``, or ``host`` request header field. ``:authority``
+header field has precedence over ``host``.
+
+Hot swapping
+------------
+
+nghttpx supports hot swapping using signals. The hot swapping in
+nghttpx is multi step process. First send USR2 signal to nghttpx
+process. It will do fork and execute new executable, using same
+command-line arguments and environment variables.
+
+As of nghttpx version 1.20.0, that is all you have to do. The new
+main process sends QUIT signal to the original process, when it is
+ready to serve requests, to shut it down gracefully.
+
+For earlier versions of nghttpx, you have to do one more thing. At
+this point, both current and new processes can accept requests. To
+gracefully shutdown current process, send QUIT signal to current
+nghttpx process. When all existing frontend connections are done, the
+current process will exit. At this point, only new nghttpx process
+exists and serves incoming requests.
+
+If you want to just reload configuration file without executing new
+binary, send SIGHUP to nghttpx main process.
+
+Re-opening log files
+--------------------
+
+When rotating log files, it is desirable to re-open log files after
+log rotation daemon renamed existing log files. To tell nghttpx to
+re-open log files, send USR1 signal to nghttpx process. It will
+re-open files specified by :option:`--accesslog-file` and
+:option:`--errorlog-file` options.
+
+Multiple frontend addresses
+---------------------------
+
+nghttpx can listen on multiple frontend addresses. To specify them,
+just use :option:`--frontend` (or its shorthand :option:`-f`) option
+repeatedly. TLS can be enabled or disabled per frontend address
+basis. For example, to listen on port 443 with TLS enabled, and on
+port 80 without TLS:
+
+.. code-block:: text
+
+ frontend=*,443
+ frontend=*,80;no-tls
+
+
+Multiple backend addresses
+--------------------------
+
+nghttpx supports multiple backend addresses. To specify them, just
+use :option:`--backend` (or its shorthand :option:`-b`) option
+repeatedly. For example, to use ``192.168.0.10:8080`` and
+``192.168.0.11:8080``, use command-line like this:
+``-b192.168.0.10,8080 -b192.168.0.11,8080``. In configuration file,
+this looks like:
+
+.. code-block:: text
+
+ backend=192.168.0.10,8080
+ backend=192.168.0.11,8008
+
+nghttpx can route request to different backend according to request
+host and path. For example, to route request destined to host
+``doc.example.com`` to backend server ``docserv:3000``, you can write
+like so:
+
+.. code-block:: text
+
+ backend=docserv,3000;doc.example.com/
+
+When you write this option in command-line, you should enclose
+argument with single or double quotes, since the character ``;`` has a
+special meaning in shell.
+
+To route, request to request path ``/foo`` to backend server
+``[::1]:8080``, you can write like so:
+
+.. code-block:: text
+
+ backend=::1,8080;/foo
+
+If the last character of path pattern is ``/``, all request paths
+which start with that pattern match:
+
+.. code-block:: text
+
+ backend=::1,8080;/bar/
+
+The request path ``/bar/buzz`` matches the ``/bar/``.
+
+You can use ``*`` at the end of the path pattern to make it wildcard
+pattern. ``*`` must match at least one character:
+
+.. code-block:: text
+
+ backend=::1,8080;/sample*
+
+The request path ``/sample1/foo`` matches the ``/sample*`` pattern.
+
+Of course, you can specify both host and request path at the same
+time:
+
+.. code-block:: text
+
+ backend=192.168.0.10,8080;example.com/foo
+
+We can use ``*`` in the left most position of host to achieve wildcard
+suffix match. If ``*`` is the left most character, then the remaining
+string should match the request host suffix. ``*`` must match at
+least one character. For example, ``*.example.com`` matches
+``www.example.com`` and ``dev.example.com``, and does not match
+``example.com`` and ``nghttp2.org``. The exact match (without ``*``)
+always takes precedence over wildcard match.
+
+One important thing you have to remember is that we have to specify
+default routing pattern for so called "catch all" pattern. To write
+"catch all" pattern, just specify backend server address, without
+pattern.
+
+Usually, host is the value of ``Host`` header field. In HTTP/2, the
+value of ``:authority`` pseudo header field is used.
+
+When you write multiple backend addresses sharing the same routing
+pattern, they are used as load balancing. For example, to use 2
+servers ``serv1:3000`` and ``serv2:3000`` for request host
+``example.com`` and path ``/myservice``, you can write like so:
+
+.. code-block:: text
+
+ backend=serv1,3000;example.com/myservice
+ backend=serv2,3000;example.com/myservice
+
+You can also specify backend application protocol in
+:option:`--backend` option using ``proto`` keyword after pattern.
+Utilizing this allows ngttpx to route certain request to HTTP/2, other
+requests to HTTP/1. For example, to route requests to ``/ws/`` in
+backend HTTP/1.1 connection, and use backend HTTP/2 for other
+requests, do this:
+
+.. code-block:: text
+
+ backend=serv1,3000;/;proto=h2
+ backend=serv1,3000;/ws/;proto=http/1.1
+
+The default backend protocol is HTTP/1.1.
+
+TLS can be enabled per pattern basis:
+
+.. code-block:: text
+
+ backend=serv1,8443;/;proto=h2;tls
+ backend=serv2,8080;/ws/;proto=http/1.1
+
+In the above case, connection to serv1 will be encrypted by TLS. On
+the other hand, connection to serv2 will not be encrypted by TLS.
+
+Dynamic hostname lookup
+-----------------------
+
+By default, nghttpx performs backend hostname lookup at start up, or
+configuration reload, and keeps using them in its entire session. To
+make nghttpx perform hostname lookup dynamically, use ``dns``
+parameter in :option:`--backend` option, like so:
+
+.. code-block:: text
+
+ backend=foo.example.com,80;;dns
+
+nghttpx will cache resolved addresses for certain period of time. To
+change this cache period, use :option:`--dns-cache-timeout`.
+
+Enable PROXY protocol
+---------------------
+
+PROXY protocol can be enabled per frontend. In order to enable PROXY
+protocol, use ``proxyproto`` parameter in :option:`--frontend` option,
+like so:
+
+.. code-block:: text
+
+ frontend=*,443;proxyproto
+
+nghttpx supports both PROXY protocol v1 and v2. AF_UNIX in PROXY
+protocol version 2 is ignored.
+
+Session affinity
+----------------
+
+Two kinds of session affinity are available: client IP, and HTTP
+Cookie.
+
+To enable client IP based affinity, specify ``affinity=ip`` parameter
+in :option:`--backend` option. If PROXY protocol is enabled, then an
+address obtained from PROXY protocol is taken into consideration.
+
+To enable HTTP Cookie based affinity, specify ``affinity=cookie``
+parameter, and specify a name of cookie in ``affinity-cookie-name``
+parameter. Optionally, a Path attribute can be specified in
+``affinity-cookie-path`` parameter:
+
+.. code-block:: text
+
+ backend=127.0.0.1,3000;;affinity=cookie;affinity-cookie-name=nghttpxlb;affinity-cookie-path=/
+
+Secure attribute of cookie is set if client connection is protected by
+TLS. ``affinity-cookie-stickiness`` specifies the stickiness of this
+affinity. If ``loose`` is given, which is the default, removing or
+adding a backend server might break affinity. While ``strict`` is
+given, removing the designated backend server breaks affinity, but
+adding new backend server does not cause breakage.
+
+PSK cipher suites
+-----------------
+
+nghttpx supports pre-shared key (PSK) cipher suites for both frontend
+and backend TLS connections. For frontend connection, use
+:option:`--psk-secrets` option to specify a file which contains PSK
+identity and secrets. The format of the file is
+``<identity>:<hex-secret>``, where ``<identity>`` is PSK identity, and
+``<hex-secret>`` is PSK secret in hex, like so:
+
+.. code-block:: text
+
+ client1:9567800e065e078085c241d54a01c6c3f24b3bab71a606600f4c6ad2c134f3b9
+ client2:b1376c3f8f6dcf7c886c5bdcceecd1e6f1d708622b6ddd21bda26ebd0c0bca99
+
+nghttpx server accepts any of the identity and secret pairs in the
+file. The default cipher suite list does not contain PSK cipher
+suites. In order to use PSK, PSK cipher suite must be enabled by
+using :option:`--ciphers` option. The desired PSK cipher suite may be
+listed in `HTTP/2 cipher block list
+<https://tools.ietf.org/html/rfc7540#appendix-A>`_. In order to use
+such PSK cipher suite with HTTP/2, disable HTTP/2 cipher block list by
+using :option:`--no-http2-cipher-block-list` option. But you should
+understand its implications.
+
+At the time of writing, even if only PSK cipher suites are specified
+in :option:`--ciphers` option, certificate and private key are still
+required.
+
+For backend connection, use :option:`--client-psk-secrets` option to
+specify a file which contains single PSK identity and secret. The
+format is the same as the file used by :option:`--psk-secrets`
+described above, but only first identity and secret pair is solely
+used, like so:
+
+.. code-block:: text
+
+ client2:b1376c3f8f6dcf7c886c5bdcceecd1e6f1d708622b6ddd21bda26ebd0c0bca99
+
+The default cipher suite list does not contain PSK cipher suites. In
+order to use PSK, PSK cipher suite must be enabled by using
+:option:`--client-ciphers` option. The desired PSK cipher suite may
+be listed in `HTTP/2 cipher block list
+<https://tools.ietf.org/html/rfc7540#appendix-A>`_. In order to use
+such PSK cipher suite with HTTP/2, disable HTTP/2 cipher block list by
+using :option:`--client-no-http2-cipher-block-list` option. But you
+should understand its implications.
+
+TLSv1.3
+-------
+
+As of nghttpx v1.34.0, if it is built with OpenSSL 1.1.1 or later, it
+supports TLSv1.3. 0-RTT data is supported, but by default its
+processing is postponed until TLS handshake completes to mitigate
+replay attack. This costs extra round trip and reduces effectiveness
+of 0-RTT data. :option:`--tls-no-postpone-early-data` makes nghttpx
+not wait for handshake to complete before forwarding request included
+in 0-RTT to get full potential of 0-RTT data. In this case, nghttpx
+adds ``Early-Data: 1`` header field when forwarding a request to a
+backend server. All backend servers should recognize this header
+field and understand that there is a risk for replay attack. See `RFC
+8470 <https://tools.ietf.org/html/rfc8470>`_ for ``Early-Data`` header
+field.
+
+nghttpx disables anti replay protection provided by OpenSSL. The anti
+replay protection of OpenSSL requires that a resumed request must hit
+the same server which generates the session ticket. Therefore it
+might not work nicely in a deployment where there are multiple nghttpx
+instances sharing ticket encryption keys via memcached.
+
+Because TLSv1.3 completely changes the semantics of cipher suite
+naming scheme and structure, nghttpx provides the new option
+:option:`--tls13-ciphers` and :option:`--tls13-client-ciphers` to
+change preferred cipher list for TLSv1.3.
+
+WebSockets over HTTP/2
+----------------------
+
+nghttpx supports `RFC 8441 <https://tools.ietf.org/html/rfc8441>`_
+Bootstrapping WebSockets with HTTP/2 for both frontend and backend
+connections. This feature is enabled by default and no configuration
+is required.
+
+WebSockets over HTTP/3 is also supported.
+
+HTTP/3
+------
+
+nghttpx supports HTTP/3 if it is built with HTTP/3 support enabled.
+HTTP/3 support is experimental.
+
+In order to listen UDP port to receive HTTP/3 traffic,
+:option:`--frontend` option must have ``quic`` parameter:
+
+.. code-block:: text
+
+ frontend=*,443;quic
+
+The above example makes nghttpx receive HTTP/3 traffic on UDP
+port 443.
+
+nghttpx does not support HTTP/3 on backend connection.
+
+Hot swapping (SIGUSR2) or configuration reload (SIGHUP) require eBPF
+program. Without eBPF, old worker processes keep getting HTTP/3
+traffic and do not work as intended. The QUIC keying material to
+encrypt Connection ID must be set with
+:option:`--frontend-quic-secret-file` and must provide the existing
+keys in order to keep the existing connections alive during reload.
+
+The construction of Connection ID closely follows Block Cipher CID
+Algorithm described in `QUIC-LB draft
+<https://datatracker.ietf.org/doc/html/draft-ietf-quic-load-balancers>`_.
+A Connection ID that nghttpx generates is always 20 bytes long. It
+uses first 2 bits as a configuration ID. The remaining bits in the
+first byte are reserved and random. The next 4 bytes are server ID.
+The next 4 bytes are used to route UDP datagram to a correct
+``SO_REUSEPORT`` socket. The remaining bytes are randomly generated.
+The server ID and the next 12 bytes are encrypted with AES-ECB. The
+key is derived from the keying materials stored in a file specified by
+:option:`--frontend-quic-secret-file`. The first 2 bits of keying
+material in the file is used as a configuration ID. The remaining
+bits and following 3 bytes are reserved and unused. The next 32 bytes
+are used as an initial secret. The remaining 32 bytes are used as a
+salt. The encryption key is generated by `HKDF
+<https://datatracker.ietf.org/doc/html/rfc5869>`_ with SHA256 and
+these keying materials and ``connection id encryption key`` as info.
+
+In order announce that HTTP/3 endpoint is available, you should
+specify alt-svc header field. For example, the following options send
+alt-svc header field in HTTP/1.1 and HTTP/2 response:
+
+.. code-block:: text
+
+ altsvc=h3,443,,,ma=3600
+ http2-altsvc=h3,443,,,ma=3600
+
+Migration from nghttpx v1.18.x or earlier
+-----------------------------------------
+
+As of nghttpx v1.19.0, :option:`--ciphers` option only changes cipher
+list for frontend TLS connection. In order to change cipher list for
+backend connection, use :option:`--client-ciphers` option.
+
+Similarly, :option:`--no-http2-cipher-block-list` option only disables
+HTTP/2 cipher block list for frontend connection. In order to disable
+HTTP/2 cipher block list for backend connection, use
+:option:`--client-no-http2-cipher-block-list` option.
+
+``--accept-proxy-protocol`` option was deprecated. Instead, use
+``proxyproto`` parameter in :option:`--frontend` option to enable
+PROXY protocol support per frontend.
+
+Migration from nghttpx v1.8.0 or earlier
+----------------------------------------
+
+As of nghttpx 1.9.0, ``--frontend-no-tls`` and ``--backend-no-tls``
+have been removed.
+
+To disable encryption on frontend connection, use ``no-tls`` keyword
+in :option:`--frontend` potion:
+
+.. code-block:: text
+
+ frontend=*,3000;no-tls
+
+The TLS encryption is now disabled on backend connection in all modes
+by default. To enable encryption on backend connection, use ``tls``
+keyword in :option:`--backend` option:
+
+.. code-block:: text
+
+ backend=127.0.0.1,8080;tls
+
+As of nghttpx 1.9.0, ``--http2-bridge``, ``--client`` and
+``--client-proxy`` options have been removed. These functionality can
+be used using combinations of options.
+
+Use following option instead of ``--http2-bridge``:
+
+.. code-block:: text
+
+ backend=<ADDR>,<PORT>;;proto=h2;tls
+
+Use following options instead of ``--client``:
+
+.. code-block:: text
+
+ frontend=<ADDR>,<PORT>;no-tls
+ backend=<ADDR>,<PORT>;;proto=h2;tls
+
+Use following options instead of ``--client-proxy``:
+
+.. code-block:: text
+
+ http2-proxy=yes
+ frontend=<ADDR>,<PORT>;no-tls
+ backend=<ADDR>,<PORT>;;proto=h2;tls
+
+We also removed ``--backend-http2-connections-per-worker`` option. It
+was present because previously the number of backend h2 connection was
+statically configured, and defaulted to 1. Now the number of backend
+h2 connection is increased on demand. We know the maximum number of
+concurrent streams per connection. When we push as many request as
+the maximum concurrency to the one connection, we create another new
+connection so that we can distribute load and avoid delay the request
+processing. This is done automatically without any configuration.
diff --git a/doc/sources/security.rst b/doc/sources/security.rst
new file mode 100644
index 0000000..5a8fcd0
--- /dev/null
+++ b/doc/sources/security.rst
@@ -0,0 +1,33 @@
+Security Process
+================
+
+If you find a vulnerability in our software, please send the email to
+"tatsuhiro.t at gmail dot com" about its details instead of submitting
+issues on github issue page. It is a standard practice not to
+disclose vulnerability information publicly until a fixed version is
+released, or mitigation is worked out. In the future, we may setup a
+dedicated mail address for this purpose.
+
+If we identify that the reported issue is really a vulnerability, we
+open a new security advisory draft using `GitHub security feature
+<https://github.com/nghttp2/nghttp2/security>`_ and discuss the
+mitigation and bug fixes there. The fixes are committed to the
+private repository.
+
+We write the security advisory and get CVE number from GitHub
+privately. We also discuss the disclosure date to the public.
+
+We make a new release with the fix at the same time when the
+vulnerability is disclosed to public.
+
+At least 7 days before the public disclosure date, we open a new issue
+on `nghttp2 issue tracker
+<https://github.com/nghttp2/nghttp2/issues>`_ which notifies that the
+upcoming release will have a security fix. The ``SECURITY`` label is
+attached to this kind of issue. The issue is not opened if a
+vulnerability is already disclosed, and it is publicly known that
+nghttp2 is affected by that.
+
+Before few hours of new release, we merge the fixes to the master
+branch (and/or a release branch if necessary) and make a new release.
+Security advisory is disclosed on GitHub.
diff --git a/doc/sources/tutorial-client.rst b/doc/sources/tutorial-client.rst
new file mode 100644
index 0000000..95a6230
--- /dev/null
+++ b/doc/sources/tutorial-client.rst
@@ -0,0 +1,464 @@
+Tutorial: HTTP/2 client
+=========================
+
+In this tutorial, we are going to write a very primitive HTTP/2
+client. The complete source code, `libevent-client.c`_, is attached at
+the end of this page. It also resides in the examples directory in
+the archive or repository.
+
+This simple client takes a single HTTPS URI and retrieves the resource
+at the URI. The synopsis is:
+
+.. code-block:: text
+
+ $ libevent-client HTTPS_URI
+
+We use libevent in this tutorial to handle networking I/O. Please
+note that nghttp2 itself does not depend on libevent.
+
+The client starts with some libevent and OpenSSL setup in the
+``main()`` and ``run()`` functions. This setup isn't specific to
+nghttp2, but one thing you should look at is setup of ALPN. Client
+tells application protocols that it supports to server via ALPN::
+
+ static SSL_CTX *create_ssl_ctx(void) {
+ SSL_CTX *ssl_ctx;
+ ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+ if (!ssl_ctx) {
+ errx(1, "Could not create SSL/TLS context: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+ SSL_CTX_set_options(ssl_ctx,
+ SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
+ SSL_OP_NO_COMPRESSION |
+ SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+
+ SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
+
+ return ssl_ctx;
+ }
+
+Here we see ``SSL_CTX_get_alpn_protos()`` function call. We instructs
+OpenSSL to notify the server that we support h2, ALPN identifier for
+HTTP/2.
+
+The example client defines a couple of structs:
+
+We define and use a ``http2_session_data`` structure to store data
+related to the HTTP/2 session::
+
+ typedef struct {
+ nghttp2_session *session;
+ struct evdns_base *dnsbase;
+ struct bufferevent *bev;
+ http2_stream_data *stream_data;
+ } http2_session_data;
+
+Since this program only handles one URI, it uses only one stream. We
+store the single stream's data in a ``http2_stream_data`` structure
+and the ``stream_data`` points to it. The ``http2_stream_data``
+structure is defined as follows::
+
+ typedef struct {
+ /* The NULL-terminated URI string to retrieve. */
+ const char *uri;
+ /* Parsed result of the |uri| */
+ struct http_parser_url *u;
+ /* The authority portion of the |uri|, not NULL-terminated */
+ char *authority;
+ /* The path portion of the |uri|, including query, not
+ NULL-terminated */
+ char *path;
+ /* The length of the |authority| */
+ size_t authoritylen;
+ /* The length of the |path| */
+ size_t pathlen;
+ /* The stream ID of this stream */
+ int32_t stream_id;
+ } http2_stream_data;
+
+We create and initialize these structures in
+``create_http2_session_data()`` and ``create_http2_stream_data()``
+respectively.
+
+``initiate_connection()`` is called to start the connection to the
+remote server. It's defined as::
+
+ static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
+ const char *host, uint16_t port,
+ http2_session_data *session_data) {
+ int rv;
+ struct bufferevent *bev;
+ SSL *ssl;
+
+ ssl = create_ssl(ssl_ctx);
+ bev = bufferevent_openssl_socket_new(
+ evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
+ BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
+ bufferevent_enable(bev, EV_READ | EV_WRITE);
+ bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
+ rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
+ AF_UNSPEC, host, port);
+
+ if (rv != 0) {
+ errx(1, "Could not connect to the remote host %s", host);
+ }
+ session_data->bev = bev;
+ }
+
+``initiate_connection()`` creates a bufferevent for the connection and
+sets up three callbacks: ``readcb``, ``writecb``, and ``eventcb``.
+
+The ``eventcb()`` is invoked by the libevent event loop when an event
+(e.g. connection has been established, timeout, etc.) occurs on the
+underlying network socket::
+
+ static void eventcb(struct bufferevent *bev, short events, void *ptr) {
+ http2_session_data *session_data = (http2_session_data *)ptr;
+ if (events & BEV_EVENT_CONNECTED) {
+ int fd = bufferevent_getfd(bev);
+ int val = 1;
+ const unsigned char *alpn = NULL;
+ unsigned int alpnlen = 0;
+ SSL *ssl;
+
+ fprintf(stderr, "Connected\n");
+
+ ssl = bufferevent_openssl_get_ssl(session_data->bev);
+
+ SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
+
+ if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
+ fprintf(stderr, "h2 is not negotiated\n");
+ delete_http2_session_data(session_data);
+ return;
+ }
+
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+ initialize_nghttp2_session(session_data);
+ send_client_connection_header(session_data);
+ submit_request(session_data);
+ if (session_send(session_data) != 0) {
+ delete_http2_session_data(session_data);
+ }
+ return;
+ }
+ if (events & BEV_EVENT_EOF) {
+ warnx("Disconnected from the remote host");
+ } else if (events & BEV_EVENT_ERROR) {
+ warnx("Network error");
+ } else if (events & BEV_EVENT_TIMEOUT) {
+ warnx("Timeout");
+ }
+ delete_http2_session_data(session_data);
+ }
+
+Here we validate that HTTP/2 is negotiated, and if not, drop
+connection.
+
+For ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR``, and ``BEV_EVENT_TIMEOUT``
+events, we just simply tear down the connection.
+
+The ``BEV_EVENT_CONNECTED`` event is invoked when the SSL/TLS
+handshake has completed successfully. After this we're ready to begin
+communicating via HTTP/2.
+
+The ``initialize_nghttp2_session()`` function initializes the nghttp2
+session object and several callbacks::
+
+ static void initialize_nghttp2_session(http2_session_data *session_data) {
+ nghttp2_session_callbacks *callbacks;
+
+ nghttp2_session_callbacks_new(&callbacks);
+
+ nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
+
+ nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
+ on_frame_recv_callback);
+
+ nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+ callbacks, on_data_chunk_recv_callback);
+
+ nghttp2_session_callbacks_set_on_stream_close_callback(
+ callbacks, on_stream_close_callback);
+
+ nghttp2_session_callbacks_set_on_header_callback(callbacks,
+ on_header_callback);
+
+ nghttp2_session_callbacks_set_on_begin_headers_callback(
+ callbacks, on_begin_headers_callback);
+
+ nghttp2_session_client_new(&session_data->session, callbacks, session_data);
+
+ nghttp2_session_callbacks_del(callbacks);
+ }
+
+Since we are creating a client, we use `nghttp2_session_client_new()`
+to initialize the nghttp2 session object. The callbacks setup are
+explained later.
+
+The `delete_http2_session_data()` function destroys ``session_data``
+and frees its bufferevent, so the underlying connection is closed. It
+also calls `nghttp2_session_del()` to delete the nghttp2 session
+object.
+
+A HTTP/2 connection begins by sending the client connection preface,
+which is a 24 byte magic byte string (:macro:`NGHTTP2_CLIENT_MAGIC`),
+followed by a SETTINGS frame. The 24 byte magic string is sent
+automatically by nghttp2. We send the SETTINGS frame in
+``send_client_connection_header()``::
+
+ static void send_client_connection_header(http2_session_data *session_data) {
+ nghttp2_settings_entry iv[1] = {
+ {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
+ int rv;
+
+ /* client 24 bytes magic string will be sent by nghttp2 library */
+ rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
+ ARRLEN(iv));
+ if (rv != 0) {
+ errx(1, "Could not submit SETTINGS: %s", nghttp2_strerror(rv));
+ }
+ }
+
+Here we specify SETTINGS_MAX_CONCURRENT_STREAMS as 100. This is not
+needed for this tiny example program, it just demonstrates use of the
+SETTINGS frame. To queue the SETTINGS frame for transmission, we call
+`nghttp2_submit_settings()`. Note that `nghttp2_submit_settings()`
+only queues the frame for transmission, and doesn't actually send it.
+All ``nghttp2_submit_*()`` family functions have this property. To
+actually send the frame, `nghttp2_session_send()` has to be called,
+which is described (and called) later.
+
+After the transmission of the client connection header, we enqueue the
+HTTP request in the ``submit_request()`` function::
+
+ static void submit_request(http2_session_data *session_data) {
+ int32_t stream_id;
+ http2_stream_data *stream_data = session_data->stream_data;
+ const char *uri = stream_data->uri;
+ const struct http_parser_url *u = stream_data->u;
+ nghttp2_nv hdrs[] = {
+ MAKE_NV2(":method", "GET"),
+ MAKE_NV(":scheme", &uri[u->field_data[UF_SCHEMA].off],
+ u->field_data[UF_SCHEMA].len),
+ MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
+ MAKE_NV(":path", stream_data->path, stream_data->pathlen)};
+ fprintf(stderr, "Request headers:\n");
+ print_headers(stderr, hdrs, ARRLEN(hdrs));
+ stream_id = nghttp2_submit_request(session_data->session, NULL, hdrs,
+ ARRLEN(hdrs), NULL, stream_data);
+ if (stream_id < 0) {
+ errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id));
+ }
+
+ stream_data->stream_id = stream_id;
+ }
+
+We build the HTTP request header fields in ``hdrs``, which is an array
+of :type:`nghttp2_nv`. There are four header fields to be sent:
+``:method``, ``:scheme``, ``:authority``, and ``:path``. To queue the
+HTTP request, we call `nghttp2_submit_request()`. The ``stream_data``
+is passed via the *stream_user_data* parameter, which is helpfully
+later passed back to callback functions.
+
+`nghttp2_submit_request()` returns the newly assigned stream ID for
+the request.
+
+The next bufferevent callback is ``readcb()``, which is invoked when
+data is available to read from the bufferevent input buffer::
+
+ static void readcb(struct bufferevent *bev, void *ptr) {
+ http2_session_data *session_data = (http2_session_data *)ptr;
+ ssize_t readlen;
+ struct evbuffer *input = bufferevent_get_input(bev);
+ size_t datalen = evbuffer_get_length(input);
+ unsigned char *data = evbuffer_pullup(input, -1);
+
+ readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
+ if (readlen < 0) {
+ warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
+ delete_http2_session_data(session_data);
+ return;
+ }
+ if (evbuffer_drain(input, (size_t)readlen) != 0) {
+ warnx("Fatal error: evbuffer_drain failed");
+ delete_http2_session_data(session_data);
+ return;
+ }
+ if (session_send(session_data) != 0) {
+ delete_http2_session_data(session_data);
+ return;
+ }
+ }
+
+In this function we feed all unprocessed, received data to the nghttp2
+session object using the `nghttp2_session_mem_recv()` function.
+`nghttp2_session_mem_recv()` processes the received data and may
+invoke nghttp2 callbacks and queue frames for transmission. Since
+there may be pending frames for transmission, we call immediately
+``session_send()`` to send them. ``session_send()`` is defined as
+follows::
+
+ static int session_send(http2_session_data *session_data) {
+ int rv;
+
+ rv = nghttp2_session_send(session_data->session);
+ if (rv != 0) {
+ warnx("Fatal error: %s", nghttp2_strerror(rv));
+ return -1;
+ }
+ return 0;
+ }
+
+The `nghttp2_session_send()` function serializes pending frames into
+wire format and calls the ``send_callback()`` function to send them.
+``send_callback()`` has type :type:`nghttp2_send_callback` and is
+defined as::
+
+ static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
+ size_t length, int flags _U_, void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ struct bufferevent *bev = session_data->bev;
+ bufferevent_write(bev, data, length);
+ return (ssize_t)length;
+ }
+
+Since we use bufferevent to abstract network I/O, we just write the
+data to the bufferevent object. Note that `nghttp2_session_send()`
+continues to write all frames queued so far. If we were writing the
+data to the non-blocking socket directly using the ``write()`` system
+call, we'd soon receive an ``EAGAIN`` or ``EWOULDBLOCK`` error, since
+sockets have a limited send buffer. If that happens, it's possible to
+return :macro:`NGHTTP2_ERR_WOULDBLOCK` to signal the nghttp2 library
+to stop sending further data. When writing to a bufferevent, you
+should regulate the amount of data written, to avoid possible huge
+memory consumption. In this example client however we don't implement
+a limit. To see how to regulate the amount of buffered data, see the
+``send_callback()`` in the server tutorial.
+
+The third bufferevent callback is ``writecb()``, which is invoked when
+all data written in the bufferevent output buffer has been sent::
+
+ static void writecb(struct bufferevent *bev _U_, void *ptr) {
+ http2_session_data *session_data = (http2_session_data *)ptr;
+ if (nghttp2_session_want_read(session_data->session) == 0 &&
+ nghttp2_session_want_write(session_data->session) == 0 &&
+ evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
+ delete_http2_session_data(session_data);
+ }
+ }
+
+As described earlier, we just write off all data in `send_callback()`,
+so there is no data to write in this function. All we have to do is
+check if the connection should be dropped or not. The nghttp2 session
+object keeps track of reception and transmission of GOAWAY frames and
+other error conditions. Using this information, the nghttp2 session
+object can state whether the connection should be dropped or not.
+More specifically, when both `nghttp2_session_want_read()` and
+`nghttp2_session_want_write()` return 0, the connection is no-longer
+required and can be closed. Since we're using bufferevent and its
+deferred callback option, the bufferevent output buffer may still
+contain pending data when the ``writecb()`` is called. To handle this
+situation, we also check whether the output buffer is empty or not. If
+all of these conditions are met, then we drop the connection.
+
+Now let's look at the remaining nghttp2 callbacks setup in the
+``initialize_nghttp2_setup()`` function.
+
+A server responds to the request by first sending a HEADERS frame.
+The HEADERS frame consists of response header name/value pairs, and
+the ``on_header_callback()`` is called for each name/value pair::
+
+ static int on_header_callback(nghttp2_session *session _U_,
+ const nghttp2_frame *frame, const uint8_t *name,
+ size_t namelen, const uint8_t *value,
+ size_t valuelen, uint8_t flags _U_,
+ void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ switch (frame->hd.type) {
+ case NGHTTP2_HEADERS:
+ if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
+ session_data->stream_data->stream_id == frame->hd.stream_id) {
+ /* Print response headers for the initiated request. */
+ print_header(stderr, name, namelen, value, valuelen);
+ break;
+ }
+ }
+ return 0;
+ }
+
+In this tutorial, we just print the name/value pairs on stderr.
+
+After the HEADERS frame has been fully received (and thus all response
+header name/value pairs have been received), the
+``on_frame_recv_callback()`` function is called::
+
+ static int on_frame_recv_callback(nghttp2_session *session _U_,
+ const nghttp2_frame *frame, void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ switch (frame->hd.type) {
+ case NGHTTP2_HEADERS:
+ if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
+ session_data->stream_data->stream_id == frame->hd.stream_id) {
+ fprintf(stderr, "All headers received\n");
+ }
+ break;
+ }
+ return 0;
+ }
+
+``on_frame_recv_callback()`` is called for other frame types too.
+
+In this tutorial, we are just interested in the HTTP response HEADERS
+frame. We check the frame type and its category (it should be
+:macro:`NGHTTP2_HCAT_RESPONSE` for HTTP response HEADERS). We also
+check its stream ID.
+
+Next, zero or more DATA frames can be received. The
+``on_data_chunk_recv_callback()`` function is invoked when a chunk of
+data is received from the remote peer::
+
+ static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
+ uint8_t flags _U_, int32_t stream_id,
+ const uint8_t *data, size_t len,
+ void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ if (session_data->stream_data->stream_id == stream_id) {
+ fwrite(data, len, 1, stdout);
+ }
+ return 0;
+ }
+
+In our case, a chunk of data is HTTP response body. After checking the
+stream ID, we just write the received data to stdout. Note the output
+in the terminal may be corrupted if the response body contains some
+binary data.
+
+The ``on_stream_close_callback()`` function is invoked when the stream
+is about to close::
+
+ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
+ nghttp2_error_code error_code,
+ void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ int rv;
+
+ if (session_data->stream_data->stream_id == stream_id) {
+ fprintf(stderr, "Stream %d closed with error_code=%d\n", stream_id,
+ error_code);
+ rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
+ if (rv != 0) {
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ }
+ return 0;
+ }
+
+If the stream ID matches the one we initiated, it means that its
+stream is going to be closed. Since we have finished receiving
+resource we wanted (or the stream was reset by RST_STREAM from the
+remote peer), we call `nghttp2_session_terminate_session()` to
+commence closure of the HTTP/2 session gracefully. If you have
+some data associated for the stream to be closed, you may delete it
+here.
diff --git a/doc/sources/tutorial-hpack.rst b/doc/sources/tutorial-hpack.rst
new file mode 100644
index 0000000..36e82d9
--- /dev/null
+++ b/doc/sources/tutorial-hpack.rst
@@ -0,0 +1,126 @@
+Tutorial: HPACK API
+===================
+
+In this tutorial, we describe basic use of nghttp2's HPACK API. We
+briefly describe the APIs for deflating and inflating header fields.
+The full example of using these APIs, `deflate.c`_, is attached at the
+end of this page. It also resides in the examples directory in the
+archive or repository.
+
+Deflating (encoding) headers
+----------------------------
+
+First we need to initialize a :type:`nghttp2_hd_deflater` object using
+the `nghttp2_hd_deflate_new()` function::
+
+ int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
+ size_t deflate_hd_table_bufsize_max);
+
+This function allocates a :type:`nghttp2_hd_deflater` object,
+initializes it, and assigns its pointer to ``*deflater_ptr``. The
+*deflate_hd_table_bufsize_max* is the upper bound of header table size
+the deflater will use. This will limit the memory usage by the
+deflater object for the dynamic header table. If in doubt, just
+specify 4096 here, which is the default upper bound of dynamic header
+table buffer size.
+
+To encode header fields, use the `nghttp2_hd_deflate_hd()` function::
+
+ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
+ uint8_t *buf, size_t buflen,
+ const nghttp2_nv *nva, size_t nvlen);
+
+The *deflater* is the deflater object initialized by
+`nghttp2_hd_deflate_new()` described above. The encoded byte string is
+written to the buffer *buf*, which has length *buflen*. The *nva* is
+a pointer to an array of headers fields, each of type
+:type:`nghttp2_nv`. *nvlen* is the number of header fields which
+*nva* contains.
+
+It is important to initialize and assign all members of
+:type:`nghttp2_nv`. For security sensitive header fields (such as
+cookies), set the :macro:`NGHTTP2_NV_FLAG_NO_INDEX` flag in
+:member:`nghttp2_nv.flags`. Setting this flag prevents recovery of
+sensitive header fields by compression based attacks: This is achieved
+by not inserting the header field into the dynamic header table.
+
+`nghttp2_hd_deflate_hd()` processes all headers given in *nva*. The
+*nva* must include all request or response header fields to be sent in
+one HEADERS (or optionally following (multiple) CONTINUATION
+frame(s)). The *buf* must have enough space to store the encoded
+result, otherwise the function will fail. To estimate the upper bound
+of the encoded result length, use `nghttp2_hd_deflate_bound()`::
+
+ size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
+ const nghttp2_nv *nva, size_t nvlen);
+
+Pass this function the same parameters (*deflater*, *nva*, and
+*nvlen*) which will be passed to `nghttp2_hd_deflate_hd()`.
+
+Subsequent calls to `nghttp2_hd_deflate_hd()` will use the current
+encoder state and perform differential encoding, which yields HPAC's
+fundamental compression gain.
+
+If `nghttp2_hd_deflate_hd()` fails, the failure is fatal and any
+further calls with the same deflater object will fail. Thus it's very
+important to use `nghttp2_hd_deflate_bound()` to determine the
+required size of the output buffer.
+
+To delete a :type:`nghttp2_hd_deflater` object, use the
+`nghttp2_hd_deflate_del()` function.
+
+Inflating (decoding) headers
+----------------------------
+
+A :type:`nghttp2_hd_inflater` object is used to inflate compressed
+header data. To initialize the object, use
+`nghttp2_hd_inflate_new()`::
+
+ int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
+
+To inflate header data, use `nghttp2_hd_inflate_hd2()`::
+
+ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
+ nghttp2_nv *nv_out, int *inflate_flags,
+ const uint8_t *in, size_t inlen,
+ int in_final);
+
+`nghttp2_hd_inflate_hd2()` reads a stream of bytes and outputs a
+single header field at a time. Multiple calls are normally required to
+read a full stream of bytes and output all of the header fields.
+
+The *inflater* is the inflater object initialized above. The *nv_out*
+is a pointer to a :type:`nghttp2_nv` into which one header field may
+be stored. The *in* is a pointer to input data, and *inlen* is its
+length. The caller is not required to specify the whole deflated
+header data via *in* at once: Instead it can call this function
+multiple times as additional data bytes become available. If
+*in_final* is nonzero, it tells the function that the passed data is
+the final sequence of deflated header data.
+
+The *inflate_flags* is an output parameter; on success the function
+sets it to a bitset of flags. It will be described later.
+
+This function returns when each header field is inflated. When this
+happens, the function sets the :macro:`NGHTTP2_HD_INFLATE_EMIT` flag
+in *inflate_flags*, and a header field is stored in *nv_out*. The
+return value indicates the number of bytes read from *in* processed so
+far, which may be less than *inlen*. The caller should call the
+function repeatedly until all bytes are processed. Processed bytes
+should be removed from *in*, and *inlen* should be adjusted
+appropriately.
+
+If *in_final* is nonzero and all given data was processed, the
+function sets the :macro:`NGHTTP2_HD_INFLATE_FINAL` flag in
+*inflate_flags*. When you see this flag set, call the
+`nghttp2_hd_inflate_end_headers()` function.
+
+If *in_final* is zero and the :macro:`NGHTTP2_HD_INFLATE_EMIT` flag is
+not set, it indicates that all given data was processed. The caller
+is required to pass additional data.
+
+Example usage of `nghttp2_hd_inflate_hd2()` is shown in the
+`inflate_header_block()` function in `deflate.c`_.
+
+Finally, to delete a :type:`nghttp2_hd_inflater` object, use
+`nghttp2_hd_inflate_del()`.
diff --git a/doc/sources/tutorial-server.rst b/doc/sources/tutorial-server.rst
new file mode 100644
index 0000000..41680bd
--- /dev/null
+++ b/doc/sources/tutorial-server.rst
@@ -0,0 +1,577 @@
+Tutorial: HTTP/2 server
+=========================
+
+In this tutorial, we are going to write a single-threaded, event-based
+HTTP/2 web server, which supports HTTPS only. It can handle concurrent
+multiple requests, but only the GET method is supported. The complete
+source code, `libevent-server.c`_, is attached at the end of this
+page. The source also resides in the examples directory in the
+archive or repository.
+
+This simple server takes 3 arguments: The port number to listen on,
+the path to your SSL/TLS private key file, and the path to your
+certificate file. The synopsis is:
+
+.. code-block:: text
+
+ $ libevent-server PORT /path/to/server.key /path/to/server.crt
+
+We use libevent in this tutorial to handle networking I/O. Please
+note that nghttp2 itself does not depend on libevent.
+
+The server starts with some libevent and OpenSSL setup in the
+``main()`` and ``run()`` functions. This setup isn't specific to
+nghttp2, but one thing you should look at is setup of ALPN callback.
+The ALPN callback is used by the server to select application
+protocols offered by client. In ALPN, client sends the list of
+supported application protocols, and server selects one of them. We
+provide the callback for it::
+
+ static int alpn_select_proto_cb(SSL *ssl _U_, const unsigned char **out,
+ unsigned char *outlen, const unsigned char *in,
+ unsigned int inlen, void *arg _U_) {
+ int rv;
+
+ rv = nghttp2_select_alpn(out, outlen, in, inlen);
+
+ if (rv != 1) {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+ }
+
+ static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
+ SSL_CTX *ssl_ctx;
+ EC_KEY *ecdh;
+
+ ssl_ctx = SSL_CTX_new(SSLv23_server_method());
+
+ ...
+
+ SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
+
+ return ssl_ctx;
+ }
+
+In ``alpn_select_proto_cb()``, we use `nghttp2_select_alpn()` to
+select application protocol. The `nghttp2_select_alpn()` returns 1
+only if it selected h2 (ALPN identifier for HTTP/2), and out
+parameters were assigned accordingly.
+
+Next, let's take a look at the main structures used by the example
+application:
+
+We use the ``app_context`` structure to store application-wide data::
+
+ struct app_context {
+ SSL_CTX *ssl_ctx;
+ struct event_base *evbase;
+ };
+
+We use the ``http2_session_data`` structure to store session-level
+(which corresponds to one HTTP/2 connection) data::
+
+ typedef struct http2_session_data {
+ struct http2_stream_data root;
+ struct bufferevent *bev;
+ app_context *app_ctx;
+ nghttp2_session *session;
+ char *client_addr;
+ } http2_session_data;
+
+We use the ``http2_stream_data`` structure to store stream-level data::
+
+ typedef struct http2_stream_data {
+ struct http2_stream_data *prev, *next;
+ char *request_path;
+ int32_t stream_id;
+ int fd;
+ } http2_stream_data;
+
+A single HTTP/2 session can have multiple streams. To manage them, we
+use a doubly linked list: The first element of this list is pointed
+to by the ``root->next`` in ``http2_session_data``. Initially,
+``root->next`` is ``NULL``.
+
+libevent's bufferevent structure is used to perform network I/O, with
+the pointer to the bufferevent stored in the ``http2_session_data``
+structure. Note that the bufferevent object is kept in
+``http2_session_data`` and not in ``http2_stream_data``. This is
+because ``http2_stream_data`` is just a logical stream multiplexed
+over the single connection managed by the bufferevent in
+``http2_session_data``.
+
+We first create a listener object to accept incoming connections.
+libevent's ``struct evconnlistener`` is used for this purpose::
+
+ static void start_listen(struct event_base *evbase, const char *service,
+ app_context *app_ctx) {
+ int rv;
+ struct addrinfo hints;
+ struct addrinfo *res, *rp;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ #ifdef AI_ADDRCONFIG
+ hints.ai_flags |= AI_ADDRCONFIG;
+ #endif /* AI_ADDRCONFIG */
+
+ rv = getaddrinfo(NULL, service, &hints, &res);
+ if (rv != 0) {
+ errx(1, NULL);
+ }
+ for (rp = res; rp; rp = rp->ai_next) {
+ struct evconnlistener *listener;
+ listener = evconnlistener_new_bind(
+ evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
+ 16, rp->ai_addr, (int)rp->ai_addrlen);
+ if (listener) {
+ freeaddrinfo(res);
+
+ return;
+ }
+ }
+ errx(1, "Could not start listener");
+ }
+
+We specify the ``acceptcb`` callback, which is called when a new connection is
+accepted::
+
+ static void acceptcb(struct evconnlistener *listener _U_, int fd,
+ struct sockaddr *addr, int addrlen, void *arg) {
+ app_context *app_ctx = (app_context *)arg;
+ http2_session_data *session_data;
+
+ session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
+
+ bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
+ }
+
+Here we create the ``http2_session_data`` object. The connection's
+bufferevent is initialized at the same time. We specify three
+callbacks for the bufferevent: ``readcb``, ``writecb``, and
+``eventcb``.
+
+The ``eventcb()`` callback is invoked by the libevent event loop when an event
+(e.g. connection has been established, timeout, etc.) occurs on the
+underlying network socket::
+
+ static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
+ http2_session_data *session_data = (http2_session_data *)ptr;
+ if (events & BEV_EVENT_CONNECTED) {
+ const unsigned char *alpn = NULL;
+ unsigned int alpnlen = 0;
+ SSL *ssl;
+
+ fprintf(stderr, "%s connected\n", session_data->client_addr);
+
+ ssl = bufferevent_openssl_get_ssl(session_data->bev);
+
+ SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
+
+ if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
+ fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);
+ delete_http2_session_data(session_data);
+ return;
+ }
+
+ initialize_nghttp2_session(session_data);
+
+ if (send_server_connection_header(session_data) != 0 ||
+ session_send(session_data) != 0) {
+ delete_http2_session_data(session_data);
+ return;
+ }
+
+ return;
+ }
+ if (events & BEV_EVENT_EOF) {
+ fprintf(stderr, "%s EOF\n", session_data->client_addr);
+ } else if (events & BEV_EVENT_ERROR) {
+ fprintf(stderr, "%s network error\n", session_data->client_addr);
+ } else if (events & BEV_EVENT_TIMEOUT) {
+ fprintf(stderr, "%s timeout\n", session_data->client_addr);
+ }
+ delete_http2_session_data(session_data);
+ }
+
+Here we validate that HTTP/2 is negotiated, and if not, drop
+connection.
+
+For the ``BEV_EVENT_EOF``, ``BEV_EVENT_ERROR``, and
+``BEV_EVENT_TIMEOUT`` events, we just simply tear down the connection.
+The ``delete_http2_session_data()`` function destroys the
+``http2_session_data`` object and its associated bufferevent member.
+As a result, the underlying connection is closed.
+
+The
+``BEV_EVENT_CONNECTED`` event is invoked when SSL/TLS handshake has
+completed successfully. After this we are ready to begin communicating
+via HTTP/2.
+
+The ``initialize_nghttp2_session()`` function initializes the nghttp2
+session object and several callbacks::
+
+ static void initialize_nghttp2_session(http2_session_data *session_data) {
+ nghttp2_session_callbacks *callbacks;
+
+ nghttp2_session_callbacks_new(&callbacks);
+
+ nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
+
+ nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
+ on_frame_recv_callback);
+
+ nghttp2_session_callbacks_set_on_stream_close_callback(
+ callbacks, on_stream_close_callback);
+
+ nghttp2_session_callbacks_set_on_header_callback(callbacks,
+ on_header_callback);
+
+ nghttp2_session_callbacks_set_on_begin_headers_callback(
+ callbacks, on_begin_headers_callback);
+
+ nghttp2_session_server_new(&session_data->session, callbacks, session_data);
+
+ nghttp2_session_callbacks_del(callbacks);
+ }
+
+Since we are creating a server, we use `nghttp2_session_server_new()`
+to initialize the nghttp2 session object. We also setup 5 callbacks
+for the nghttp2 session, these are explained later.
+
+The server now begins by sending the server connection preface, which
+always consists of a SETTINGS frame.
+``send_server_connection_header()`` configures and submits it::
+
+ static int send_server_connection_header(http2_session_data *session_data) {
+ nghttp2_settings_entry iv[1] = {
+ {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
+ int rv;
+
+ rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
+ ARRLEN(iv));
+ if (rv != 0) {
+ warnx("Fatal error: %s", nghttp2_strerror(rv));
+ return -1;
+ }
+ return 0;
+ }
+
+In the example SETTINGS frame we've set
+SETTINGS_MAX_CONCURRENT_STREAMS to 100. `nghttp2_submit_settings()`
+is used to queue the frame for transmission, but note it only queues
+the frame for transmission, and doesn't actually send it. All
+functions in the ``nghttp2_submit_*()`` family have this property. To
+actually send the frame, `nghttp2_session_send()` should be used, as
+described later.
+
+Since bufferevent may buffer more than the first 24 bytes from the client, we
+have to process them here since libevent won't invoke callback functions for
+this pending data. To process the received data, we call the
+``session_recv()`` function::
+
+ static int session_recv(http2_session_data *session_data) {
+ ssize_t readlen;
+ struct evbuffer *input = bufferevent_get_input(session_data->bev);
+ size_t datalen = evbuffer_get_length(input);
+ unsigned char *data = evbuffer_pullup(input, -1);
+
+ readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
+ if (readlen < 0) {
+ warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
+ return -1;
+ }
+ if (evbuffer_drain(input, (size_t)readlen) != 0) {
+ warnx("Fatal error: evbuffer_drain failed");
+ return -1;
+ }
+ if (session_send(session_data) != 0) {
+ return -1;
+ }
+ return 0;
+ }
+
+In this function, we feed all unprocessed but already received data to
+the nghttp2 session object using the `nghttp2_session_mem_recv()`
+function. The `nghttp2_session_mem_recv()` function processes the data
+and may both invoke the previously setup callbacks and also queue
+outgoing frames. To send any pending outgoing frames, we immediately
+call ``session_send()``.
+
+The ``session_send()`` function is defined as follows::
+
+ static int session_send(http2_session_data *session_data) {
+ int rv;
+ rv = nghttp2_session_send(session_data->session);
+ if (rv != 0) {
+ warnx("Fatal error: %s", nghttp2_strerror(rv));
+ return -1;
+ }
+ return 0;
+ }
+
+The `nghttp2_session_send()` function serializes the frame into wire
+format and calls the ``send_callback()``, which is of type
+:type:`nghttp2_send_callback`. The ``send_callback()`` is defined as
+follows::
+
+ static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
+ size_t length, int flags _U_, void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ struct bufferevent *bev = session_data->bev;
+ /* Avoid excessive buffering in server side. */
+ if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
+ OUTPUT_WOULDBLOCK_THRESHOLD) {
+ return NGHTTP2_ERR_WOULDBLOCK;
+ }
+ bufferevent_write(bev, data, length);
+ return (ssize_t)length;
+ }
+
+Since we use bufferevent to abstract network I/O, we just write the
+data to the bufferevent object. Note that `nghttp2_session_send()`
+continues to write all frames queued so far. If we were writing the
+data to a non-blocking socket directly using the ``write()`` system
+call in the ``send_callback()``, we'd soon receive an ``EAGAIN`` or
+``EWOULDBLOCK`` error since sockets have a limited send buffer. If
+that happens, it's possible to return :macro:`NGHTTP2_ERR_WOULDBLOCK`
+to signal the nghttp2 library to stop sending further data. But here,
+when writing to the bufferevent, we have to regulate the amount data
+to buffered ourselves to avoid using huge amounts of memory. To
+achieve this, we check the size of the output buffer and if it reaches
+more than or equal to ``OUTPUT_WOULDBLOCK_THRESHOLD`` bytes, we stop
+writing data and return :macro:`NGHTTP2_ERR_WOULDBLOCK`.
+
+The next bufferevent callback is ``readcb()``, which is invoked when
+data is available to read in the bufferevent input buffer::
+
+ static void readcb(struct bufferevent *bev _U_, void *ptr) {
+ http2_session_data *session_data = (http2_session_data *)ptr;
+ if (session_recv(session_data) != 0) {
+ delete_http2_session_data(session_data);
+ return;
+ }
+ }
+
+In this function, we just call ``session_recv()`` to process incoming
+data.
+
+The third bufferevent callback is ``writecb()``, which is invoked when all
+data in the bufferevent output buffer has been sent::
+
+ static void writecb(struct bufferevent *bev, void *ptr) {
+ http2_session_data *session_data = (http2_session_data *)ptr;
+ if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
+ return;
+ }
+ if (nghttp2_session_want_read(session_data->session) == 0 &&
+ nghttp2_session_want_write(session_data->session) == 0) {
+ delete_http2_session_data(session_data);
+ return;
+ }
+ if (session_send(session_data) != 0) {
+ delete_http2_session_data(session_data);
+ return;
+ }
+ }
+
+First we check whether we should drop the connection or not. The
+nghttp2 session object keeps track of reception and transmission of
+GOAWAY frames and other error conditions as well. Using this
+information, the nghttp2 session object can state whether the
+connection should be dropped or not. More specifically, if both
+`nghttp2_session_want_read()` and `nghttp2_session_want_write()`
+return 0, the connection is no-longer required and can be closed.
+Since we are using bufferevent and its deferred callback option, the
+bufferevent output buffer may still contain pending data when the
+``writecb()`` is called. To handle this, we check whether the output
+buffer is empty or not. If all of these conditions are met, we drop
+connection.
+
+Otherwise, we call ``session_send()`` to process the pending output
+data. Remember that in ``send_callback()``, we must not write all data to
+bufferevent to avoid excessive buffering. We continue processing pending data
+when the output buffer becomes empty.
+
+We have already described the nghttp2 callback ``send_callback()``. Let's
+learn about the remaining nghttp2 callbacks setup in
+``initialize_nghttp2_setup()`` function.
+
+The ``on_begin_headers_callback()`` function is invoked when the reception of
+a header block in HEADERS or PUSH_PROMISE frame is started::
+
+ static int on_begin_headers_callback(nghttp2_session *session,
+ const nghttp2_frame *frame,
+ void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ http2_stream_data *stream_data;
+
+ if (frame->hd.type != NGHTTP2_HEADERS ||
+ frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
+ return 0;
+ }
+ stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
+ nghttp2_session_set_stream_user_data(session, frame->hd.stream_id,
+ stream_data);
+ return 0;
+ }
+
+We are only interested in the HEADERS frame in this function. Since
+the HEADERS frame has several roles in the HTTP/2 protocol, we check
+that it is a request HEADERS, which opens new stream. If the frame is
+a request HEADERS, we create a ``http2_stream_data`` object to store
+the stream related data. We associate the created
+``http2_stream_data`` object with the stream in the nghttp2 session
+object using `nghttp2_set_stream_user_data()`. The
+``http2_stream_data`` object can later be easily retrieved from the
+stream, without searching through the doubly linked list.
+
+In this example server, we want to serve files relative to the current working
+directory in which the program was invoked. Each header name/value pair is
+emitted via ``on_header_callback`` function, which is called after
+``on_begin_headers_callback()``::
+
+ static int on_header_callback(nghttp2_session *session,
+ const nghttp2_frame *frame, const uint8_t *name,
+ size_t namelen, const uint8_t *value,
+ size_t valuelen, uint8_t flags _U_,
+ void *user_data _U_) {
+ http2_stream_data *stream_data;
+ const char PATH[] = ":path";
+ switch (frame->hd.type) {
+ case NGHTTP2_HEADERS:
+ if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
+ break;
+ }
+ stream_data =
+ nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
+ if (!stream_data || stream_data->request_path) {
+ break;
+ }
+ if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
+ size_t j;
+ for (j = 0; j < valuelen && value[j] != '?'; ++j)
+ ;
+ stream_data->request_path = percent_decode(value, j);
+ }
+ break;
+ }
+ return 0;
+ }
+
+We search for the ``:path`` header field among the request headers and
+store the requested path in the ``http2_stream_data`` object. In this
+example program, we ignore the ``:method`` header field and always
+treat the request as a GET request.
+
+The ``on_frame_recv_callback()`` function is invoked when a frame is
+fully received::
+
+ static int on_frame_recv_callback(nghttp2_session *session,
+ const nghttp2_frame *frame, void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ http2_stream_data *stream_data;
+ switch (frame->hd.type) {
+ case NGHTTP2_DATA:
+ case NGHTTP2_HEADERS:
+ /* Check that the client request has finished */
+ if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
+ stream_data =
+ nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
+ /* For DATA and HEADERS frame, this callback may be called after
+ on_stream_close_callback. Check that stream still alive. */
+ if (!stream_data) {
+ return 0;
+ }
+ return on_request_recv(session, session_data, stream_data);
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+ }
+
+First we retrieve the ``http2_stream_data`` object associated with the
+stream in ``on_begin_headers_callback()`` using
+`nghttp2_session_get_stream_user_data()`. If the requested path
+cannot be served for some reason (e.g. file is not found), we send a
+404 response using ``error_reply()``. Otherwise, we open
+the requested file and send its content. We send the header field
+``:status`` as a single response header.
+
+Sending the file content is performed by the ``send_response()`` function::
+
+ static int send_response(nghttp2_session *session, int32_t stream_id,
+ nghttp2_nv *nva, size_t nvlen, int fd) {
+ int rv;
+ nghttp2_data_provider data_prd;
+ data_prd.source.fd = fd;
+ data_prd.read_callback = file_read_callback;
+
+ rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd);
+ if (rv != 0) {
+ warnx("Fatal error: %s", nghttp2_strerror(rv));
+ return -1;
+ }
+ return 0;
+ }
+
+nghttp2 uses the :type:`nghttp2_data_provider` structure to send the
+entity body to the remote peer. The ``source`` member of this
+structure is a union, which can be either a void pointer or an int
+(which is intended to be used as file descriptor). In this example
+server, we use it as a file descriptor. We also set the
+``file_read_callback()`` callback function to read the contents of the
+file::
+
+ static ssize_t file_read_callback(nghttp2_session *session _U_,
+ int32_t stream_id _U_, uint8_t *buf,
+ size_t length, uint32_t *data_flags,
+ nghttp2_data_source *source,
+ void *user_data _U_) {
+ int fd = source->fd;
+ ssize_t r;
+ while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
+ ;
+ if (r == -1) {
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
+ }
+ if (r == 0) {
+ *data_flags |= NGHTTP2_DATA_FLAG_EOF;
+ }
+ return r;
+ }
+
+If an error occurs while reading the file, we return
+:macro:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. This tells the
+library to send RST_STREAM to the stream. When all data has been
+read, the :macro:`NGHTTP2_DATA_FLAG_EOF` flag is set to signal nghttp2
+that we have finished reading the file.
+
+The `nghttp2_submit_response()` function is used to send the response to the
+remote peer.
+
+The ``on_stream_close_callback()`` function is invoked when the stream
+is about to close::
+
+ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
+ uint32_t error_code _U_, void *user_data) {
+ http2_session_data *session_data = (http2_session_data *)user_data;
+ http2_stream_data *stream_data;
+
+ stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
+ if (!stream_data) {
+ return 0;
+ }
+ remove_stream(session_data, stream_data);
+ delete_http2_stream_data(stream_data);
+ return 0;
+ }
+
+Lastly, we destroy the ``http2_stream_data`` object in this function,
+since the stream is about to close and we no longer need the object.
diff --git a/doc/tutorial-client.rst.in b/doc/tutorial-client.rst.in
new file mode 100644
index 0000000..4f7fcfc
--- /dev/null
+++ b/doc/tutorial-client.rst.in
@@ -0,0 +1,6 @@
+.. include:: @top_srcdir@/doc/sources/tutorial-client.rst
+
+libevent-client.c
+-----------------
+
+.. literalinclude:: @top_srcdir@/examples/libevent-client.c
diff --git a/doc/tutorial-hpack.rst.in b/doc/tutorial-hpack.rst.in
new file mode 100644
index 0000000..832dedf
--- /dev/null
+++ b/doc/tutorial-hpack.rst.in
@@ -0,0 +1,6 @@
+.. include:: @top_srcdir@/doc/sources/tutorial-hpack.rst
+
+deflate.c
+---------
+
+.. literalinclude:: @top_srcdir@/examples/deflate.c
diff --git a/doc/tutorial-server.rst.in b/doc/tutorial-server.rst.in
new file mode 100644
index 0000000..1972266
--- /dev/null
+++ b/doc/tutorial-server.rst.in
@@ -0,0 +1,6 @@
+.. include:: @top_srcdir@/doc/sources/tutorial-server.rst
+
+libevent-server.c
+-----------------
+
+.. literalinclude:: @top_srcdir@/examples/libevent-server.c
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..25a7261
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,78 @@
+FROM debian:12 as build
+
+RUN apt-get update && \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+ git clang make binutils autoconf automake autotools-dev libtool \
+ pkg-config \
+ zlib1g-dev libev-dev libjemalloc-dev ruby-dev libc-ares-dev bison \
+ libelf-dev
+
+RUN git clone --depth 1 -b OpenSSL_1_1_1w+quic https://github.com/quictls/openssl && \
+ cd openssl && \
+ ./config --openssldir=/etc/ssl && \
+ make -j$(nproc) && \
+ make install_sw && \
+ cd .. && \
+ rm -rf openssl
+
+RUN git clone --depth 1 -b v1.1.0 https://github.com/ngtcp2/nghttp3 && \
+ cd nghttp3 && \
+ autoreconf -i && \
+ ./configure --enable-lib-only && \
+ make -j$(nproc) && \
+ make install-strip && \
+ cd .. && \
+ rm -rf nghttp3
+
+RUN git clone --depth 1 -b v1.2.0 https://github.com/ngtcp2/ngtcp2 && \
+ cd ngtcp2 && \
+ autoreconf -i && \
+ ./configure --enable-lib-only \
+ LIBTOOL_LDFLAGS="-static-libtool-libs" \
+ OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -lpthread" \
+ PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
+ make -j$(nproc) && \
+ make install-strip && \
+ cd .. && \
+ rm -rf ngtcp2
+
+RUN git clone --depth 1 -b v1.3.0 https://github.com/libbpf/libbpf && \
+ cd libbpf && \
+ PREFIX=/usr/local make -C src install && \
+ cd .. && \
+ rm -rf libbpf
+
+RUN git clone --depth 1 https://github.com/nghttp2/nghttp2.git && \
+ cd nghttp2 && \
+ git submodule update --init && \
+ autoreconf -i && \
+ ./configure --disable-examples --disable-hpack-tools \
+ --with-mruby --with-neverbleed \
+ --enable-http3 --with-libbpf \
+ CC=clang CXX=clang++ \
+ LIBTOOL_LDFLAGS="-static-libtool-libs" \
+ OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -pthread" \
+ LIBEV_LIBS="-l:libev.a" \
+ JEMALLOC_LIBS="-l:libjemalloc.a" \
+ LIBCARES_LIBS="-l:libcares.a" \
+ ZLIB_LIBS="-l:libz.a" \
+ LIBBPF_LIBS="-L/usr/local/lib64 -l:libbpf.a -l:libelf.a" \
+ LDFLAGS="-static-libgcc -static-libstdc++" \
+ PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
+ make -j$(nproc) install-strip && \
+ cd .. && \
+ rm -rf nghttp2
+
+FROM gcr.io/distroless/base-debian12
+
+COPY --from=build \
+ /usr/local/share/nghttp2/ \
+ /usr/local/share/nghttp2/
+COPY --from=build \
+ /usr/local/bin/h2load \
+ /usr/local/bin/nghttpx \
+ /usr/local/bin/nghttp \
+ /usr/local/bin/nghttpd \
+ /usr/local/bin/
+COPY --from=build /usr/local/lib/nghttp2/reuseport_kern.o \
+ /usr/local/lib/nghttp2/
diff --git a/docker/README.rst b/docker/README.rst
new file mode 100644
index 0000000..e08af23
--- /dev/null
+++ b/docker/README.rst
@@ -0,0 +1,25 @@
+Dockerfile
+==========
+
+Dockerfile creates the applications bundled with nghttp2.
+These applications are:
+
+- nghttp
+- nghttpd
+- nghttpx
+- h2load
+
+HTTP/3 and eBPF features are enabled.
+
+In order to run nghttpx with HTTP/3 endpoint, you need to run the
+image with the escalated privilege. Here is the example command-line
+to run nghttpx to listen to HTTP/3 on port 443, assuming that the
+current directory contains a private key and a certificate in
+server.key and server.crt respectively:
+
+.. code-block:: text
+
+ $ docker run --rm -it -v /path/to/certs:/shared --net=host --privileged \
+ nghttp2 nghttpx \
+ /shared/server.key /shared/server.crt \
+ -f'*,443;quic'