diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:34:15 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:34:15 +0000 |
commit | afea5f9539cbf1eeaa85ec77d79eb2f59724f470 (patch) | |
tree | 2a4eba394a6bc60d2eaa8304d91168a07225d51e /doc | |
parent | Initial commit. (diff) | |
download | nghttp2-upstream/1.52.0.tar.xz nghttp2-upstream/1.52.0.zip |
Adding upstream version 1.52.0.upstream/1.52.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'doc')
50 files changed, 13614 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..53f63c3 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,362 @@ +# 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_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_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_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_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..80afe39 --- /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 --npn-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..72dd590 --- /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 --npn-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..167f027 --- /dev/null +++ b/doc/h2load.1 @@ -0,0 +1,531 @@ +.\" 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" "Feb 13, 2023" "1.52.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 "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. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-npn\-list=<LIST> +Comma delimited list of ALPN protocol identifier sorted +in the order of preference. That means most desirable +protocol comes first. This is used in both ALPN and +NPN. 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\%\-\-npn\-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 "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. +.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 "on the wire". 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..0f65849 --- /dev/null +++ b/doc/h2load.1.rst @@ -0,0 +1,435 @@ + +.. 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:: --npn-list=<LIST> + + Comma delimited list of ALPN protocol identifier sorted + in the order of preference. That means most desirable + protocol comes first. This is used in both ALPN and + NPN. 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:`--npn-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..3886a65 --- /dev/null +++ b/doc/mkapiref.py @@ -0,0 +1,344 @@ +#!/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) + content = re.sub(r':enum:', ':macro:', 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..ca58440 --- /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" "Feb 13, 2023" "1.52.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 "anchor" 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 "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. +.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..704da5b --- /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" "Feb 13, 2023" "1.52.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..450fa24 --- /dev/null +++ b/doc/nghttpx.1 @@ -0,0 +1,2769 @@ +.\" 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" "Feb 13, 2023" "1.52.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 +"no\-tls" parameter is used in \fI\%\-\-frontend\fP option. +.UNINDENT +.INDENT 0.0 +.TP +.B <CERT> +Set path to server\(aqs certificate. Required unless +"no\-tls" 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 "unix:" (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 "\fI/\fP". If it ends with "\fI/\fP", it matches +all request path in its subtree. To deal with the +request to the directory without trailing slash, the +path which ends with "\fI/\fP" also matches the request path +which only lacks trailing \(aq\fI/\fP\(aq (e.g., path "\fI/foo/\fP" +matches request path "\fI/foo\fP"). If it does not end with +"\fI/\fP", 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, +"\fI/\fP" 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\(aqt allow +empty path. To workaround this, we assume that CONNECT +method has "\fI/\fP" 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 "*" 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. +.sp +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,"\fI/\fP". 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 "\fI/foo*\fP" matches "\fI/foo/\fP" and +"\fI/foobar\fP". But it does not match "\fI/foo\fP", or "\fI/fo\fP". +.sp +If <PATTERN> is omitted or empty string, "\fI/\fP" 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 (".." and ".") are resolved and +removed. +.sp +For example, \fI\%\-b\fP\(aq127.0.0.1,8080;nghttp2.org/httpbin/\(aq +matches the request host "nghttp2.org" and the request +path "\fI/httpbin/get\fP", but does not match the request host +"nghttp2.org" and the request path "\fI/index.html\fP". +.sp +The multiple <PATTERN>s can be specified, delimiting +them by ":". 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 ";". 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. +.sp +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). +.sp +TLS can be enabled by specifying optional "tls" +parameter. TLS is not enabled by default. +.sp +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 +.sp +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. +.sp +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. +.sp +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". +.sp +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. +.sp +If "redirect\-if\-not\-tls" 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 "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. +.sp +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. +.sp +"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. +.sp +"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, \fI\%\-\-backend\-read\-timeout\fP and +\fI\%\-\-backend\-write\-timeout\fP are used. +.sp +"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. +.sp +"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. +.sp +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". +.sp +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. +.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 "unix:" (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 "api" and "healthmon" +parameters are mutually exclusive. +.sp +Optionally, TLS can be disabled by specifying "no\-tls" +parameter. TLS is enabled by default. +.sp +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 +\fI\%\-\-backend\fP option about the pattern match. +.sp +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. +.sp +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. +.sp +To accept PROXY protocol version 1 and 2 on frontend +connection, specify "proxyproto" parameter. This is +disabled by default. +.sp +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. +.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 +"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. +.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 "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. +.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 "fail" +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 "sct\-dir=<DIR>". +.sp +"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 +\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 \-\-npn\-list=<LIST> +Comma delimited list of ALPN protocol identifier sorted +in the order of preference. That means most desirable +protocol comes first. This is used in both ALPN and +NPN. 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 "unknown protocol". 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 "unknown protocol". 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 +"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. +.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 "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. +.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 +"failure" 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 "tls" +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 "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. +.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 +"Early\-Data" 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. "no\-tls" +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: "r" if SSL/TLS session was +reused. Otherwise, "." +.IP \(bu 2 +$tls_sni: SNI server name for SSL/TLS connection. +.IP \(bu 2 +$backend_host: backend host used to fulfill the +request. "\-" if backend host is not available. +.IP \(bu 2 +$backend_port: backend port used to fulfill the +request. "\-" 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 "{" and "}" for +disambiguation (e.g., ${remote_addr}). +.sp +Default: \fB$remote_addr \- \- [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"\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 "by", "for", "host", and "proto". By +default, the value of "by" and "for" 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 "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. +.sp +Default: \fBobfuscated\fP +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-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. +.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="h2,443,,,ma=3600; persist=1" +.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. 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="foo: bar" +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-add\-response\-header=<HEADER> +Specify additional header field to add to response +header set. 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="foo: bar" +.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 "*" 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 +"redirect\-if\-not\-tls" 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 "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. +.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 "\-", server Source Connection ID and +".sqlog". +.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 one of "cubic", "bbr", +and "bbr2". +.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="foo: bar" +.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 "GET" or "POST". 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 "mruby" 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 "localhost". +.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 ".." and ".". 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 = "/apps#{env.req.path}" + 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 = ["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 +.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 "api" +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 "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). +.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 "dns" 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..9bb2b5e --- /dev/null +++ b/doc/nghttpx.1.rst @@ -0,0 +1,2525 @@ + +.. 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:: --npn-list=<LIST> + + Comma delimited list of ALPN protocol identifier sorted + in the order of preference. That means most desirable + protocol comes first. This is used in both ALPN and + NPN. 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. 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. 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 one of "cubic", "bbr", + and "bbr2". + + 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..32f43c8 --- /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-14. + +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..2ee2754 --- /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/NPN. +You can set specific protocols in :option:`--npn-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:`--npn-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..a979504 --- /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 or NPN. + +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..ab27eab --- /dev/null +++ b/doc/sources/security.rst @@ -0,0 +1,38 @@ +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 will post +security advisory (which includes all the details of the vulnerability +and the possible mitigation strategies) and the patches to fix the +issue to `distros@openwall +<https://oss-security.openwall.org/wiki/mailing-lists/distros>`_ +mailing list. We also 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. + +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. We also post the +vulnerability information to `oss-security +<https://oss-security.openwall.org/wiki/mailing-lists/oss-security>`_ +mailing list. diff --git a/doc/sources/tutorial-client.rst b/doc/sources/tutorial-client.rst new file mode 100644 index 0000000..7c086a8 --- /dev/null +++ b/doc/sources/tutorial-client.rst @@ -0,0 +1,498 @@ +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 the NPN +callback. The NPN callback is used by the client to select the next +application protocol over TLS. In this tutorial, we use the +`nghttp2_select_next_protocol()` helper function to select the HTTP/2 +protocol the library supports:: + + static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg _U_) { + if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) { + errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID); + } + return SSL_TLSEXT_ERR_OK; + } + +If you are following TLS related RFC, you know that NPN is not the +standardized way to negotiate HTTP/2. NPN itself is not event +published as RFC. The standard way to negotiate HTTP/2 is ALPN, +Application-Layer Protocol Negotiation Extension, defined in `RFC 7301 +<https://tools.ietf.org/html/rfc7301>`_. The one caveat of ALPN is +that OpenSSL >= 1.0.2 is required. We use macro to enable/disable +ALPN support depending on OpenSSL version. OpenSSL's ALPN +implementation does not require callback function like the above. But +we have to instruct OpenSSL SSL_CTX to use ALPN, which we'll talk +about soon. + +The callback is added to the SSL_CTX object using +``SSL_CTX_set_next_proto_select_cb()``:: + + 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_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL); + + #if OPENSSL_VERSION_NUMBER >= 0x10002000L + SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3); + #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L + + 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_next_proto_negotiated(ssl, &alpn, &alpnlen); + #if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (alpn == NULL) { + SSL_get0_alpn_selected(ssl, &alpn, &alpnlen); + } + #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L + + 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..3142837 --- /dev/null +++ b/doc/sources/tutorial-server.rst @@ -0,0 +1,625 @@ +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 the NPN +callback. The NPN callback is used by the server to advertise which +application protocols the server supports to a client. In this +example program, when creating the ``SSL_CTX`` object, we store the +application protocol name in the wire format of NPN in a statically +allocated buffer. This is safe because we only create one ``SSL_CTX`` +object in the program's entire lifetime. + +If you are following TLS related RFC, you know that NPN is not the +standardized way to negotiate HTTP/2. NPN itself is not even +published as RFC. The standard way to negotiate HTTP/2 is ALPN, +Application-Layer Protocol Negotiation Extension, defined in `RFC 7301 +<https://tools.ietf.org/html/rfc7301>`_. The one caveat of ALPN is +that OpenSSL >= 1.0.2 is required. We use macro to enable/disable +ALPN support depending on OpenSSL version. In ALPN, client sends the +list of supported application protocols, and server selects one of +them. We provide the callback for it:: + + static unsigned char next_proto_list[256]; + static size_t next_proto_list_len; + + static int next_proto_cb(SSL *s _U_, const unsigned char **data, + unsigned int *len, void *arg _U_) { + *data = next_proto_list; + *len = (unsigned int)next_proto_list_len; + return SSL_TLSEXT_ERR_OK; + } + + #if OPENSSL_VERSION_NUMBER >= 0x10002000L + 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_next_protocol((unsigned char **)out, outlen, in, inlen); + + if (rv != 1) { + return SSL_TLSEXT_ERR_NOACK; + } + + return SSL_TLSEXT_ERR_OK; + } + #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L + + 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()); + + ... + + next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN; + memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN); + next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN; + + SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL); + + #if OPENSSL_VERSION_NUMBER >= 0x10002000L + SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL); + #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L + + return ssl_ctx; + } + +The wire format of NPN is a sequence of length prefixed strings, with +exactly one byte used to specify the length of each protocol +identifier. In this tutorial, we advertise the specific HTTP/2 +protocol version the current nghttp2 library supports, which is +exported in the identifier :macro:`NGHTTP2_PROTO_VERSION_ID`. The +``next_proto_cb()`` function is the server-side NPN callback. In the +OpenSSL implementation, we just assign the pointer to the NPN buffers +we filled in earlier. The NPN callback function is set to the +``SSL_CTX`` object using ``SSL_CTX_set_next_protos_advertised_cb()``. + +In ``alpn_select_proto_cb()``, we use `nghttp2_select_next_protocol()` +to select application protocol. The `nghttp2_select_next_protocol()` +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_next_proto_negotiated(ssl, &alpn, &alpnlen); + #if OPENSSL_VERSION_NUMBER >= 0x10002000L + if (alpn == NULL) { + SSL_get0_alpn_selected(ssl, &alpn, &alpnlen); + } + #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L + + 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 |