diff --git a/CMakeLists.txt b/CMakeLists.txt
index 926f5d7f..20ed664f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,7 @@ option(JSONSCHEMA_TESTS "Build the JSON Schema CLI tests" OFF)
option(JSONSCHEMA_CONTINUOUS "Perform a continuous JSON Schema CLI release" ON)
find_package(JSONToolkit REQUIRED)
+find_package(Hydra REQUIRED)
add_subdirectory(src)
noa_target_clang_format(SOURCES
diff --git a/DEPENDENCIES b/DEPENDENCIES
index 2b208b48..55c1b004 100644
--- a/DEPENDENCIES
+++ b/DEPENDENCIES
@@ -1,3 +1,4 @@
vendorpull https://github.com/sourcemeta/vendorpull dea311b5bfb53b6926a4140267959ae334d3ecf4
noa https://github.com/sourcemeta/noa 5ff4024902642afc9cc2f9a9e02ae9dff9d15d4f
jsontoolkit https://github.com/sourcemeta/jsontoolkit 2775ccc05af7be64dd2532694bb17274185aeec1
+hydra https://github.com/sourcemeta/hydra d5e0c314dae88b0bf2ac4eeff2c7395910e2c7e9
diff --git a/cmake/FindHydra.cmake b/cmake/FindHydra.cmake
new file mode 100644
index 00000000..40cbbe6e
--- /dev/null
+++ b/cmake/FindHydra.cmake
@@ -0,0 +1,7 @@
+if(NOT Hydra_FOUND)
+ set(HYDRA_INSTALL OFF CACHE BOOL "disable installation")
+ set(HYDRA_HTTPSERVER OFF CACHE BOOL "disable the Hydra HTTP server module")
+ set(HYDRA_BUCKET OFF CACHE BOOL "disable the Hydra bucket module")
+ add_subdirectory("${PROJECT_SOURCE_DIR}/vendor/hydra")
+ set(Hydra_FOUND ON)
+endif()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 782d3063..9ef9418f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -10,8 +10,10 @@ add_executable(jsonschema_cli
lint/enum_with_type.h)
intelligence_jsonschema_add_compile_options(jsonschema_cli)
set_target_properties(jsonschema_cli PROPERTIES OUTPUT_NAME jsonschema)
+target_link_libraries(jsonschema_cli PRIVATE sourcemeta::jsontoolkit::uri)
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::jsontoolkit::json)
target_link_libraries(jsonschema_cli PRIVATE sourcemeta::jsontoolkit::jsonschema)
+target_link_libraries(jsonschema_cli PRIVATE sourcemeta::hydra::httpclient)
configure_file(configure.h.in configure.h @ONLY)
target_include_directories(jsonschema_cli PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
diff --git a/vendor/hydra/CMakeLists.txt b/vendor/hydra/CMakeLists.txt
new file mode 100644
index 00000000..24c6ce79
--- /dev/null
+++ b/vendor/hydra/CMakeLists.txt
@@ -0,0 +1,115 @@
+cmake_minimum_required(VERSION 3.24)
+project(hydra VERSION 0.0.1 LANGUAGES C CXX
+ DESCRIPTION "A convenience networking library for modern C++")
+list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
+include(vendor/noa/cmake/noa.cmake)
+include(cmake/CompilerOptions.cmake)
+
+# Options
+option(HYDRA_HTTPCLIENT "Build the Hydra HTTP client library" ON)
+if(WIN32)
+ # TODO: Make it work on Windows. Main challenge is that uSockets
+ # relies on libuv for that platform.
+ option(HYDRA_HTTPSERVER "Build the Hydra HTTP server library" OFF)
+else()
+ option(HYDRA_HTTPSERVER "Build the Hydra HTTP server library" ON)
+endif()
+option(HYDRA_BUCKET "Build the Hydra bucket library" ON)
+option(HYDRA_TESTS "Build the Hydra tests" OFF)
+option(HYDRA_DOCS "Build the Hydra docs" OFF)
+option(HYDRA_INSTALL "Install the Hydra library" ON)
+option(HYDRA_ADDRESS_SANITIZER "Build Hydra with an address sanitizer" OFF)
+option(HYDRA_UNDEFINED_SANITIZER "Build Hydra with an undefined behavior sanitizer" OFF)
+
+if(HYDRA_INSTALL)
+ include(GNUInstallDirs)
+ include(CMakePackageConfigHelpers)
+ configure_package_config_file(
+ config.cmake.in
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
+ INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+ write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake"
+ COMPATIBILITY SameMajorVersion)
+ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
+ COMPONENT sourcemeta_hydra_dev)
+endif()
+
+if(HYDRA_HTTPCLIENT OR HYDRA_HTTPSERVER OR HYDRA_BUCKET)
+ add_subdirectory(src/http)
+endif()
+
+if(HYDRA_HTTPCLIENT OR HYDRA_BUCKET)
+ find_package(ZLIB REQUIRED)
+ find_package(BearSSL REQUIRED)
+ find_package(CURL REQUIRED)
+ add_subdirectory(src/httpclient)
+endif()
+
+if(HYDRA_HTTPSERVER)
+ find_package(uSockets REQUIRED)
+ find_package(uWebSockets REQUIRED)
+ add_subdirectory(src/httpserver)
+endif()
+
+if(HYDRA_BUCKET)
+ find_package(JSONToolkit REQUIRED COMPONENTS json uri)
+ add_subdirectory(src/bucket)
+endif()
+
+if(HYDRA_ADDRESS_SANITIZER)
+ noa_sanitizer(TYPE address)
+elseif(HYDRA_UNDEFINED_SANITIZER)
+ noa_sanitizer(TYPE undefined)
+endif()
+
+if(HYDRA_DOCS)
+ noa_target_doxygen(CONFIG "${PROJECT_SOURCE_DIR}/doxygen/Doxyfile.in"
+ OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/website")
+endif()
+
+if(PROJECT_IS_TOP_LEVEL)
+ noa_target_clang_format(SOURCES
+ src/*.cc src/*.h test/*.cc test/*.h)
+ noa_target_clang_tidy(SOURCES
+ src/*.h src/*.cc)
+endif()
+
+# Testing
+if(HYDRA_TESTS)
+ find_package(GoogleTest REQUIRED)
+ enable_testing()
+
+ if(HYDRA_HTTPCLIENT OR HYDRA_HTTPSERVER OR HYDRA_BUCKET)
+ add_subdirectory(test/unit/http)
+ endif()
+
+ if(HYDRA_HTTPCLIENT)
+ add_subdirectory(test/e2e/httpclient)
+ endif()
+
+ if(HYDRA_HTTPSERVER)
+ add_subdirectory(test/unit/httpserver)
+ find_package(JSONToolkit REQUIRED COMPONENTS json)
+ # Because we need to test with an HTTP client
+ if(HYDRA_HTTPCLIENT)
+ add_subdirectory(test/e2e/httpserver)
+ endif()
+ endif()
+
+ if(HYDRA_BUCKET)
+ add_subdirectory(test/unit/bucket)
+ add_subdirectory(test/e2e/bucket)
+ endif()
+
+ if(PROJECT_IS_TOP_LEVEL)
+ # Otherwise we need the child project to link
+ # against the sanitizers too.
+ if(NOT HYDRA_ADDRESS_SANITIZER AND NOT HYDRA_UNDEFINED_SANITIZER)
+ add_subdirectory(test/packaging)
+ endif()
+ endif()
+endif()
diff --git a/vendor/hydra/LICENSE b/vendor/hydra/LICENSE
new file mode 100644
index 00000000..1c068fce
--- /dev/null
+++ b/vendor/hydra/LICENSE
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ Hydra - An HTTP client for modern C++
+ Copyright (C) 2023 Juan Cruz Viotti
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/vendor/hydra/LICENSE-COMMERCIAL b/vendor/hydra/LICENSE-COMMERCIAL
new file mode 100644
index 00000000..2b3c48a3
--- /dev/null
+++ b/vendor/hydra/LICENSE-COMMERCIAL
@@ -0,0 +1,2 @@
+Refer to https://www.sourcemeta.com/licensing/ for learning more about
+obtaining a commercial license.
diff --git a/vendor/hydra/cmake/CompilerOptions.cmake b/vendor/hydra/cmake/CompilerOptions.cmake
new file mode 100644
index 00000000..307d2743
--- /dev/null
+++ b/vendor/hydra/cmake/CompilerOptions.cmake
@@ -0,0 +1,66 @@
+function(sourcemeta_hydra_add_compile_options target)
+ if(NOA_COMPILER_MSVC)
+ # See https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category
+ target_compile_options("${target}" PRIVATE
+ /options:strict
+ /permissive-
+ /W4
+ /WL
+ /MP
+ /sdl)
+ else()
+ target_compile_options("${target}" PRIVATE
+ -Wall
+ -Wextra
+ -Wpedantic
+ -Wshadow
+ -Wdouble-promotion
+ -Wconversion
+ -Wunused-parameter
+ -Wtrigraphs
+ -Wunreachable-code
+ -Wmissing-braces
+ -Wparentheses
+ -Wswitch
+ -Wunused-function
+ -Wunused-label
+ -Wunused-parameter
+ -Wunused-variable
+ -Wunused-value
+ -Wempty-body
+ -Wuninitialized
+ -Wshadow
+ -Wconversion
+ -Wenum-conversion
+ -Wfloat-conversion
+ -Wimplicit-fallthrough
+ -Wsign-compare
+ -Wsign-conversion
+ -Wunknown-pragmas
+ -Wnon-virtual-dtor
+ -Woverloaded-virtual
+ -Winvalid-offsetof)
+ endif()
+
+ if(NOA_COMPILER_LLVM)
+ target_compile_options("${target}" PRIVATE
+ -Wbool-conversion
+ -Wint-conversion
+ -Wpointer-sign
+ -Wconditional-uninitialized
+ -Wconstant-conversion
+ -Wnon-literal-null-conversion
+ -Wshorten-64-to-32
+ -Wdeprecated-implementations
+ -Winfinite-recursion
+ -Wnewline-eof
+ -Wfour-char-constants
+ -Wselector
+ -Wundeclared-selector
+ -Wdocumentation
+ -Wmove
+ -Wc++11-extensions
+ -Wno-exit-time-destructors
+ -Wrange-loop-analysis)
+ endif()
+endfunction()
diff --git a/vendor/hydra/cmake/FindBearSSL.cmake b/vendor/hydra/cmake/FindBearSSL.cmake
new file mode 100644
index 00000000..25c04e8d
--- /dev/null
+++ b/vendor/hydra/cmake/FindBearSSL.cmake
@@ -0,0 +1,360 @@
+if(NOT BearSSL_FOUND)
+ set(BEARSSL_DIR "${PROJECT_SOURCE_DIR}/vendor/bearssl")
+
+ set(BEARSSL_PUBLIC_HEADER "${BEARSSL_DIR}/inc/bearssl.h")
+ set(BEARSSL_PRIVATE_HEADERS
+ "${BEARSSL_DIR}/inc/bearssl_aead.h"
+ "${BEARSSL_DIR}/inc/bearssl_block.h"
+ "${BEARSSL_DIR}/inc/bearssl_ec.h"
+ "${BEARSSL_DIR}/inc/bearssl_hash.h"
+ "${BEARSSL_DIR}/inc/bearssl_hmac.h"
+ "${BEARSSL_DIR}/inc/bearssl_kdf.h"
+ "${BEARSSL_DIR}/inc/bearssl_pem.h"
+ "${BEARSSL_DIR}/inc/bearssl_prf.h"
+ "${BEARSSL_DIR}/inc/bearssl_rand.h"
+ "${BEARSSL_DIR}/inc/bearssl_rsa.h"
+ "${BEARSSL_DIR}/inc/bearssl_ssl.h"
+ "${BEARSSL_DIR}/inc/bearssl_x509.h")
+
+ set(BEARSSL_SOURCES
+ "${BEARSSL_PUBLIC_HEADER}" ${BEARSSL_PRIVATE_HEADERS}
+ "${BEARSSL_DIR}/src/kdf/hkdf.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_hashes.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_scert_single_ec.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine_default_rsavrfy.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_hs_client.t0"
+ "${BEARSSL_DIR}/src/ssl/prf.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine_default_ecdsa.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_minf2c.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_mine2g.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_io.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_minr2g.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_mine2c.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_hs_server.t0"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_hs_client.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine_default_aesccm.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_rec_ccm.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_minf2g.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_client.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_minu2g.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_rec_gcm.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_rec_chapol.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine_default_aesgcm.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_keyexport.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine_default_aescbc.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_rec_cbc.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_minv2g.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine_default_descbc.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_lru.c"
+ "${BEARSSL_DIR}/src/ssl/prf_sha384.c"
+ "${BEARSSL_DIR}/src/ssl/prf_sha256.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_hs_server.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine_default_ec.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_client_default_rsapub.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_hs_common.t0"
+ "${BEARSSL_DIR}/src/ssl/ssl_engine_default_chapol.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_scert_single_rsa.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_ccert_single_rsa.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_full_ec.c"
+ "${BEARSSL_DIR}/src/ssl/prf_md5sha1.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_client_full.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_server_full_rsa.c"
+ "${BEARSSL_DIR}/src/ssl/ssl_ccert_single_ec.c"
+ "${BEARSSL_DIR}/src/aead/gcm.c"
+ "${BEARSSL_DIR}/src/aead/ccm.c"
+ "${BEARSSL_DIR}/src/aead/eax.c"
+ "${BEARSSL_DIR}/src/config.h"
+ "${BEARSSL_DIR}/src/hash/sha2small.c"
+ "${BEARSSL_DIR}/src/hash/ghash_ctmul32.c"
+ "${BEARSSL_DIR}/src/hash/mgf1.c"
+ "${BEARSSL_DIR}/src/hash/sha1.c"
+ "${BEARSSL_DIR}/src/hash/md5sha1.c"
+ "${BEARSSL_DIR}/src/hash/dig_size.c"
+ "${BEARSSL_DIR}/src/hash/multihash.c"
+ "${BEARSSL_DIR}/src/hash/ghash_pclmul.c"
+ "${BEARSSL_DIR}/src/hash/ghash_ctmul.c"
+ "${BEARSSL_DIR}/src/hash/ghash_ctmul64.c"
+ "${BEARSSL_DIR}/src/hash/sha2big.c"
+ "${BEARSSL_DIR}/src/hash/ghash_pwr8.c"
+ "${BEARSSL_DIR}/src/hash/md5.c"
+ "${BEARSSL_DIR}/src/hash/dig_oid.c"
+ "${BEARSSL_DIR}/src/codec/enc32le.c"
+ "${BEARSSL_DIR}/src/codec/dec16le.c"
+ "${BEARSSL_DIR}/src/codec/dec64be.c"
+ "${BEARSSL_DIR}/src/codec/pemdec.t0"
+ "${BEARSSL_DIR}/src/codec/dec16be.c"
+ "${BEARSSL_DIR}/src/codec/enc32be.c"
+ "${BEARSSL_DIR}/src/codec/dec64le.c"
+ "${BEARSSL_DIR}/src/codec/enc64le.c"
+ "${BEARSSL_DIR}/src/codec/dec32be.c"
+ "${BEARSSL_DIR}/src/codec/enc16be.c"
+ "${BEARSSL_DIR}/src/codec/pemenc.c"
+ "${BEARSSL_DIR}/src/codec/ccopy.c"
+ "${BEARSSL_DIR}/src/codec/pemdec.c"
+ "${BEARSSL_DIR}/src/codec/enc64be.c"
+ "${BEARSSL_DIR}/src/codec/enc16le.c"
+ "${BEARSSL_DIR}/src/codec/dec32le.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_keygen_inner.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_pubexp.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i62_pkcs1_vrfy.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_modulus.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_oaep_encrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_pub.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_pub.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_modulus.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_pub.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i62_oaep_encrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_pkcs1_vrfy.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i32_oaep_decrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_keygen.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_oaep_decrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_pkcs1_vrfy.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_priv.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i32_priv.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_pubexp.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_oaep_unpad.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_ssl_decrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_keygen.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_pkcs1_sign.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i32_pub.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_pubexp.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_privexp.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_oaep_decrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_keygen.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i62_keygen.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i32_pkcs1_sign.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_pkcs1_sig_pad.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_priv.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i62_pkcs1_sign.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_oaep_encrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_priv.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_pkcs1_sign.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i62_pub.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_privexp.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_pkcs1_sig_unpad.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_pkcs1_sign.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i31_privexp.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i62_priv.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_oaep_encrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i62_oaep_decrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i32_oaep_encrypt.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_default_pkcs1_vrfy.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_oaep_pad.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_modulus.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i32_pkcs1_vrfy.c"
+ "${BEARSSL_DIR}/src/rsa/rsa_i15_oaep_decrypt.c"
+ "${BEARSSL_DIR}/src/ec/ec_keygen.c"
+ "${BEARSSL_DIR}/src/ec/ec_prime_i31.c"
+ "${BEARSSL_DIR}/src/ec/ec_default.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i31_vrfy_asn1.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_atr.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i15_vrfy_asn1.c"
+ "${BEARSSL_DIR}/src/ec/ec_c25519_m31.c"
+ "${BEARSSL_DIR}/src/ec/ec_c25519_i31.c"
+ "${BEARSSL_DIR}/src/ec/ec_curve25519.c"
+ "${BEARSSL_DIR}/src/ec/ec_all_m31.c"
+ "${BEARSSL_DIR}/src/ec/ec_p256_m31.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_default_sign_asn1.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_rta.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i15_vrfy_raw.c"
+ "${BEARSSL_DIR}/src/ec/ec_c25519_m15.c"
+ "${BEARSSL_DIR}/src/ec/ec_all_m15.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i31_sign_asn1.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i15_sign_raw.c"
+ "${BEARSSL_DIR}/src/ec/ec_c25519_i15.c"
+ "${BEARSSL_DIR}/src/ec/ec_secp384r1.c"
+ "${BEARSSL_DIR}/src/ec/ec_p256_m15.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i15_sign_asn1.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i31_vrfy_raw.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_default_sign_raw.c"
+ "${BEARSSL_DIR}/src/ec/ec_secp256r1.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i31_bits.c"
+ "${BEARSSL_DIR}/src/ec/ec_prime_i15.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i15_bits.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_default_vrfy_asn1.c"
+ "${BEARSSL_DIR}/src/ec/ec_secp521r1.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_default_vrfy_raw.c"
+ "${BEARSSL_DIR}/src/ec/ec_pubkey.c"
+ "${BEARSSL_DIR}/src/ec/ecdsa_i31_sign_raw.c"
+ "${BEARSSL_DIR}/src/x509/asn1.t0"
+ "${BEARSSL_DIR}/src/x509/asn1enc.c"
+ "${BEARSSL_DIR}/src/x509/encode_ec_rawder.c"
+ "${BEARSSL_DIR}/src/x509/x509_minimal.t0"
+ "${BEARSSL_DIR}/src/x509/skey_decoder.t0"
+ "${BEARSSL_DIR}/src/x509/x509_minimal_full.c"
+ "${BEARSSL_DIR}/src/x509/encode_rsa_rawder.c"
+ "${BEARSSL_DIR}/src/x509/x509_minimal.c"
+ "${BEARSSL_DIR}/src/x509/x509_decoder.t0"
+ "${BEARSSL_DIR}/src/x509/x509_knownkey.c"
+ "${BEARSSL_DIR}/src/x509/skey_decoder.c"
+ "${BEARSSL_DIR}/src/x509/encode_rsa_pk8der.c"
+ "${BEARSSL_DIR}/src/x509/encode_ec_pk8der.c"
+ "${BEARSSL_DIR}/src/x509/x509_decoder.c"
+ "${BEARSSL_DIR}/src/mac/hmac.c"
+ "${BEARSSL_DIR}/src/mac/hmac_ct.c"
+ "${BEARSSL_DIR}/src/int/i32_bitlen.c"
+ "${BEARSSL_DIR}/src/int/i31_fmont.c"
+ "${BEARSSL_DIR}/src/int/i31_decred.c"
+ "${BEARSSL_DIR}/src/int/i15_rshift.c"
+ "${BEARSSL_DIR}/src/int/i62_modpow2.c"
+ "${BEARSSL_DIR}/src/int/i32_decmod.c"
+ "${BEARSSL_DIR}/src/int/i31_encode.c"
+ "${BEARSSL_DIR}/src/int/i32_iszero.c"
+ "${BEARSSL_DIR}/src/int/i31_mulacc.c"
+ "${BEARSSL_DIR}/src/int/i15_modpow2.c"
+ "${BEARSSL_DIR}/src/int/i32_muladd.c"
+ "${BEARSSL_DIR}/src/int/i15_reduce.c"
+ "${BEARSSL_DIR}/src/int/i31_decode.c"
+ "${BEARSSL_DIR}/src/int/i15_decred.c"
+ "${BEARSSL_DIR}/src/int/i31_rshift.c"
+ "${BEARSSL_DIR}/src/int/i32_modpow.c"
+ "${BEARSSL_DIR}/src/int/i32_fmont.c"
+ "${BEARSSL_DIR}/src/int/i31_reduce.c"
+ "${BEARSSL_DIR}/src/int/i15_decode.c"
+ "${BEARSSL_DIR}/src/int/i15_fmont.c"
+ "${BEARSSL_DIR}/src/int/i31_ninv31.c"
+ "${BEARSSL_DIR}/src/int/i31_montmul.c"
+ "${BEARSSL_DIR}/src/int/i15_encode.c"
+ "${BEARSSL_DIR}/src/int/i32_div32.c"
+ "${BEARSSL_DIR}/src/int/i15_mulacc.c"
+ "${BEARSSL_DIR}/src/int/i31_muladd.c"
+ "${BEARSSL_DIR}/src/int/i32_ninv32.c"
+ "${BEARSSL_DIR}/src/int/i32_decode.c"
+ "${BEARSSL_DIR}/src/int/i31_decmod.c"
+ "${BEARSSL_DIR}/src/int/i31_tmont.c"
+ "${BEARSSL_DIR}/src/int/i31_iszero.c"
+ "${BEARSSL_DIR}/src/int/i32_encode.c"
+ "${BEARSSL_DIR}/src/int/i15_montmul.c"
+ "${BEARSSL_DIR}/src/int/i32_mulacc.c"
+ "${BEARSSL_DIR}/src/int/i15_moddiv.c"
+ "${BEARSSL_DIR}/src/int/i32_decred.c"
+ "${BEARSSL_DIR}/src/int/i31_sub.c"
+ "${BEARSSL_DIR}/src/int/i15_modpow.c"
+ "${BEARSSL_DIR}/src/int/i15_add.c"
+ "${BEARSSL_DIR}/src/int/i31_add.c"
+ "${BEARSSL_DIR}/src/int/i31_bitlen.c"
+ "${BEARSSL_DIR}/src/int/i32_montmul.c"
+ "${BEARSSL_DIR}/src/int/i15_sub.c"
+ "${BEARSSL_DIR}/src/int/i15_iszero.c"
+ "${BEARSSL_DIR}/src/int/i15_decmod.c"
+ "${BEARSSL_DIR}/src/int/i32_tmont.c"
+ "${BEARSSL_DIR}/src/int/i32_reduce.c"
+ "${BEARSSL_DIR}/src/int/i15_muladd.c"
+ "${BEARSSL_DIR}/src/int/i31_modpow2.c"
+ "${BEARSSL_DIR}/src/int/i15_tmont.c"
+ "${BEARSSL_DIR}/src/int/i15_bitlen.c"
+ "${BEARSSL_DIR}/src/int/i15_ninv15.c"
+ "${BEARSSL_DIR}/src/int/i31_modpow.c"
+ "${BEARSSL_DIR}/src/int/i32_add.c"
+ "${BEARSSL_DIR}/src/int/i32_sub.c"
+ "${BEARSSL_DIR}/src/int/i31_moddiv.c"
+ "${BEARSSL_DIR}/src/symcipher/des_tab_cbcdec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct64.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_big_cbcenc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_pwr8_cbcdec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct_ctr.c"
+ "${BEARSSL_DIR}/src/symcipher/des_ct.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_x86ni_ctrcbc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_small_ctrcbc.c"
+ "${BEARSSL_DIR}/src/symcipher/des_ct_cbcenc.c"
+ "${BEARSSL_DIR}/src/symcipher/poly1305_ctmul32.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_big_ctr.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct_ctrcbc.c"
+ "${BEARSSL_DIR}/src/symcipher/des_ct_cbcdec.c"
+ "${BEARSSL_DIR}/src/symcipher/poly1305_ctmulq.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct64_ctrcbc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_pwr8_cbcenc.c"
+ "${BEARSSL_DIR}/src/symcipher/chacha20_ct.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_big_cbcdec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_small_ctr.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_x86ni.c"
+ "${BEARSSL_DIR}/src/symcipher/des_tab_cbcenc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct64_ctr.c"
+ "${BEARSSL_DIR}/src/symcipher/des_support.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_big_ctrcbc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_small_dec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_x86ni_ctr.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_common.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct64_dec.c"
+ "${BEARSSL_DIR}/src/symcipher/des_tab.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_big_dec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_pwr8.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_small_cbcenc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct_cbcdec.c"
+ "${BEARSSL_DIR}/src/symcipher/chacha20_sse2.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct_enc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_x86ni_cbcenc.c"
+ "${BEARSSL_DIR}/src/symcipher/poly1305_ctmul.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct64_cbcdec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_pwr8_ctr.c"
+ "${BEARSSL_DIR}/src/symcipher/poly1305_i15.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct64_cbcenc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_x86ni_cbcdec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct_dec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct_cbcenc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_small_cbcdec.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_big_enc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_ct64_enc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_small_enc.c"
+ "${BEARSSL_DIR}/src/symcipher/aes_pwr8_ctrcbc.c"
+ "${BEARSSL_DIR}/src/settings.c"
+ "${BEARSSL_DIR}/src/rand/sysrng.c"
+ "${BEARSSL_DIR}/src/rand/aesctr_drbg.c"
+ "${BEARSSL_DIR}/src/rand/hmac_drbg.c"
+ "${BEARSSL_DIR}/src/inner.h")
+
+ if(WIN32)
+ # BearSSL doesn't seem to support DLLs
+ add_library(bearssl STATIC ${BEARSSL_SOURCES})
+ else()
+ add_library(bearssl ${BEARSSL_SOURCES})
+ endif()
+
+ target_include_directories(bearssl PRIVATE "${BEARSSL_DIR}/src")
+ target_include_directories(bearssl PUBLIC
+ "$"
+ "$")
+
+ add_library(BearSSL::BearSSL ALIAS bearssl)
+
+ set_target_properties(bearssl
+ PROPERTIES
+ OUTPUT_NAME bearssl
+ PUBLIC_HEADER "${BEARSSL_PUBLIC_HEADER}"
+ PRIVATE_HEADER "${BEARSSL_PRIVATE_HEADERS}"
+ C_VISIBILITY_PRESET "default"
+ C_VISIBILITY_INLINES_HIDDEN FALSE
+ WINDOWS_EXPORT_ALL_SYMBOLS TRUE
+ EXPORT_NAME bearssl)
+
+ include(GNUInstallDirs)
+ install(TARGETS bearssl
+ EXPORT bearssl
+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+ COMPONENT sourcemeta_hydra_dev
+ PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+ COMPONENT sourcemeta_hydra_dev
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ COMPONENT sourcemeta_hydra
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra
+ NAMELINK_COMPONENT sourcemeta_hydra_dev
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra_dev)
+ install(EXPORT bearssl
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/bearssl"
+ COMPONENT sourcemeta_hydra_dev)
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bearssl-config.cmake
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/bearssl.cmake\")\n"
+ "check_required_components(\"bearssl\")\n")
+ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/bearssl-config.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/bearssl"
+ COMPONENT sourcemeta_hydra_dev)
+
+ set(BearSSL_FOUND ON)
+endif()
diff --git a/vendor/hydra/cmake/FindCURL.cmake b/vendor/hydra/cmake/FindCURL.cmake
new file mode 100644
index 00000000..d3ba2906
--- /dev/null
+++ b/vendor/hydra/cmake/FindCURL.cmake
@@ -0,0 +1,476 @@
+if(NOT CURL_FOUND)
+ set(CURL_DIR "${PROJECT_SOURCE_DIR}/vendor/curl")
+
+ set(CURL_PUBLIC_HEADER "${CURL_DIR}/include/curl/curl.h")
+ set(CURL_PRIVATE_HEADERS
+ "${CURL_DIR}/include/curl/stdcheaders.h"
+ "${CURL_DIR}/include/curl/header.h"
+ "${CURL_DIR}/include/curl/options.h"
+ "${CURL_DIR}/include/curl/mprintf.h"
+ "${CURL_DIR}/include/curl/easy.h"
+ "${CURL_DIR}/include/curl/websockets.h"
+ "${CURL_DIR}/include/curl/curlver.h"
+ "${CURL_DIR}/include/curl/system.h"
+ "${CURL_DIR}/include/curl/typecheck-gcc.h"
+ "${CURL_DIR}/include/curl/multi.h"
+ "${CURL_DIR}/include/curl/urlapi.h")
+
+ add_library(curl
+ "${CURL_PUBLIC_HEADER}" ${CURL_PRIVATE_HEADERS}
+ "${CURL_DIR}/lib/strcase.c"
+ "${CURL_DIR}/lib/cf-h2-proxy.h"
+ "${CURL_DIR}/lib/easyoptions.c"
+ "${CURL_DIR}/lib/dict.c"
+ "${CURL_DIR}/lib/llist.c"
+ "${CURL_DIR}/lib/mprintf.c"
+ "${CURL_DIR}/lib/pingpong.c"
+ "${CURL_DIR}/lib/socks_gssapi.c"
+ "${CURL_DIR}/lib/memdebug.h"
+ "${CURL_DIR}/lib/psl.c"
+ "${CURL_DIR}/lib/progress.h"
+ "${CURL_DIR}/lib/url.c"
+ "${CURL_DIR}/lib/easyif.h"
+ "${CURL_DIR}/lib/curl_md4.h"
+ "${CURL_DIR}/lib/timeval.c"
+ "${CURL_DIR}/lib/http_aws_sigv4.h"
+ "${CURL_DIR}/lib/curl_get_line.c"
+ "${CURL_DIR}/lib/hmac.c"
+ "${CURL_DIR}/lib/curl_addrinfo.h"
+ "${CURL_DIR}/lib/md4.c"
+ "${CURL_DIR}/lib/curl_range.c"
+ "${CURL_DIR}/lib/idn.c"
+ "${CURL_DIR}/lib/hostsyn.c"
+ "${CURL_DIR}/lib/strtok.c"
+ "${CURL_DIR}/lib/smtp.h"
+ "${CURL_DIR}/lib/curl_threads.c"
+ "${CURL_DIR}/lib/if2ip.c"
+ "${CURL_DIR}/lib/c-hyper.c"
+ "${CURL_DIR}/lib/cf-socket.c"
+ "${CURL_DIR}/lib/http_negotiate.c"
+ "${CURL_DIR}/lib/doh.c"
+ "${CURL_DIR}/lib/curl_endian.c"
+ "${CURL_DIR}/lib/formdata.c"
+ "${CURL_DIR}/lib/easygetopt.c"
+ "${CURL_DIR}/lib/cf-https-connect.c"
+ "${CURL_DIR}/lib/mime.h"
+ "${CURL_DIR}/lib/strdup.h"
+ "${CURL_DIR}/lib/timediff.c"
+ "${CURL_DIR}/lib/fileinfo.h"
+ "${CURL_DIR}/lib/curl_ldap.h"
+ "${CURL_DIR}/lib/dynbuf.c"
+ "${CURL_DIR}/lib/amigaos.h"
+ "${CURL_DIR}/lib/telnet.h"
+ "${CURL_DIR}/lib/rand.c"
+ "${CURL_DIR}/lib/http_chunks.h"
+ "${CURL_DIR}/lib/http2.c"
+ "${CURL_DIR}/lib/strerror.h"
+ "${CURL_DIR}/lib/curl_multibyte.h"
+ "${CURL_DIR}/lib/socketpair.h"
+ "${CURL_DIR}/lib/netrc.h"
+ "${CURL_DIR}/lib/bufref.h"
+ "${CURL_DIR}/lib/dynhds.c"
+ "${CURL_DIR}/lib/curl_sasl.h"
+ "${CURL_DIR}/lib/content_encoding.c"
+ "${CURL_DIR}/lib/curl_ctype.h"
+ "${CURL_DIR}/lib/hostip.c"
+ "${CURL_DIR}/lib/curl_sspi.h"
+ "${CURL_DIR}/lib/http.h"
+ "${CURL_DIR}/lib/curl_des.h"
+ "${CURL_DIR}/lib/curl_gethostname.h"
+ "${CURL_DIR}/lib/rtsp.h"
+ "${CURL_DIR}/lib/splay.h"
+ "${CURL_DIR}/lib/escape.c"
+ "${CURL_DIR}/lib/version_win32.c"
+ "${CURL_DIR}/lib/easy.c"
+ "${CURL_DIR}/lib/rename.c"
+ "${CURL_DIR}/lib/pop3.h"
+ "${CURL_DIR}/lib/curl_path.h"
+ "${CURL_DIR}/lib/share.c"
+ "${CURL_DIR}/lib/slist.c"
+ "${CURL_DIR}/lib/inet_pton.c"
+ "${CURL_DIR}/lib/tftp.c"
+ "${CURL_DIR}/lib/curl_ntlm_core.h"
+ "${CURL_DIR}/lib/mqtt.c"
+ "${CURL_DIR}/lib/config-plan9.h"
+ "${CURL_DIR}/lib/noproxy.h"
+ "${CURL_DIR}/lib/gopher.h"
+ "${CURL_DIR}/lib/fopen.c"
+ "${CURL_DIR}/lib/multihandle.h"
+ "${CURL_DIR}/lib/socks.c"
+ "${CURL_DIR}/lib/imap.h"
+ "${CURL_DIR}/lib/parsedate.c"
+ "${CURL_DIR}/lib/curl_trc.c"
+ "${CURL_DIR}/lib/hsts.h"
+ "${CURL_DIR}/lib/warnless.c"
+ "${CURL_DIR}/lib/cf-haproxy.c"
+ "${CURL_DIR}/lib/http_digest.h"
+ "${CURL_DIR}/lib/curl_printf.h"
+ "${CURL_DIR}/lib/file.h"
+ "${CURL_DIR}/lib/cfilters.c"
+ "${CURL_DIR}/lib/ftp.h"
+ "${CURL_DIR}/lib/strtoofft.h"
+ "${CURL_DIR}/lib/cf-h1-proxy.h"
+ "${CURL_DIR}/lib/smb.h"
+ "${CURL_DIR}/lib/curl_memrchr.h"
+ "${CURL_DIR}/lib/conncache.h"
+ "${CURL_DIR}/lib/altsvc.h"
+ "${CURL_DIR}/lib/ws.h"
+ "${CURL_DIR}/lib/connect.h"
+ "${CURL_DIR}/lib/system_win32.c"
+ "${CURL_DIR}/lib/transfer.c"
+ "${CURL_DIR}/lib/curl_gssapi.h"
+ "${CURL_DIR}/lib/curl_rtmp.c"
+ "${CURL_DIR}/lib/nonblock.c"
+ "${CURL_DIR}/lib/select.c"
+ "${CURL_DIR}/lib/curl_fnmatch.h"
+ "${CURL_DIR}/lib/getinfo.h"
+ "${CURL_DIR}/lib/hostip4.c"
+ "${CURL_DIR}/lib/http1.c"
+ "${CURL_DIR}/lib/inet_ntop.h"
+ "${CURL_DIR}/lib/speedcheck.h"
+ "${CURL_DIR}/lib/urlapi.c"
+ "${CURL_DIR}/lib/ftplistparser.h"
+ "${CURL_DIR}/lib/openldap.c"
+ "${CURL_DIR}/lib/getenv.c"
+ "${CURL_DIR}/lib/setopt.h"
+ "${CURL_DIR}/lib/hash.c"
+ "${CURL_DIR}/lib/bufq.c"
+ "${CURL_DIR}/lib/http_proxy.c"
+ "${CURL_DIR}/lib/http_ntlm.h"
+ "${CURL_DIR}/lib/vquic/curl_quiche.h"
+ "${CURL_DIR}/lib/vquic/vquic.c"
+ "${CURL_DIR}/lib/vquic/curl_ngtcp2.c"
+ "${CURL_DIR}/lib/vquic/curl_msh3.h"
+ "${CURL_DIR}/lib/vquic/curl_quiche.c"
+ "${CURL_DIR}/lib/vquic/curl_ngtcp2.h"
+ "${CURL_DIR}/lib/vquic/vquic.h"
+ "${CURL_DIR}/lib/vquic/vquic_int.h"
+ "${CURL_DIR}/lib/vquic/curl_msh3.c"
+ "${CURL_DIR}/lib/cookie.h"
+ "${CURL_DIR}/lib/krb5.c"
+ "${CURL_DIR}/lib/macos.h"
+ "${CURL_DIR}/lib/headers.h"
+ "${CURL_DIR}/lib/multi.c"
+ "${CURL_DIR}/lib/sendf.h"
+ "${CURL_DIR}/lib/curl_memory.h"
+ "${CURL_DIR}/lib/cf-https-connect.h"
+ "${CURL_DIR}/lib/formdata.h"
+ "${CURL_DIR}/lib/urldata.h"
+ "${CURL_DIR}/lib/multiif.h"
+ "${CURL_DIR}/lib/curl_endian.h"
+ "${CURL_DIR}/lib/config-win32.h"
+ "${CURL_DIR}/lib/strdup.c"
+ "${CURL_DIR}/lib/mime.c"
+ "${CURL_DIR}/lib/cf-socket.h"
+ "${CURL_DIR}/lib/if2ip.h"
+ "${CURL_DIR}/lib/socks_sspi.c"
+ "${CURL_DIR}/lib/c-hyper.h"
+ "${CURL_DIR}/lib/curl_threads.h"
+ "${CURL_DIR}/lib/strtok.h"
+ "${CURL_DIR}/lib/smtp.c"
+ "${CURL_DIR}/lib/doh.h"
+ "${CURL_DIR}/lib/http_negotiate.h"
+ "${CURL_DIR}/lib/curl_setup_once.h"
+ "${CURL_DIR}/lib/curl_get_line.h"
+ "${CURL_DIR}/lib/http_aws_sigv4.c"
+ "${CURL_DIR}/lib/timeval.h"
+ "${CURL_DIR}/lib/sockaddr.h"
+ "${CURL_DIR}/lib/curl_hmac.h"
+ "${CURL_DIR}/lib/curl_range.h"
+ "${CURL_DIR}/lib/idn.h"
+ "${CURL_DIR}/lib/setup-os400.h"
+ "${CURL_DIR}/lib/curl_addrinfo.c"
+ "${CURL_DIR}/lib/curl_setup.h"
+ "${CURL_DIR}/lib/pingpong.h"
+ "${CURL_DIR}/lib/llist.h"
+ "${CURL_DIR}/lib/dict.h"
+ "${CURL_DIR}/lib/config-win32ce.h"
+ "${CURL_DIR}/lib/easyoptions.h"
+ "${CURL_DIR}/lib/strcase.h"
+ "${CURL_DIR}/lib/cf-h2-proxy.c"
+ "${CURL_DIR}/lib/url.h"
+ "${CURL_DIR}/lib/psl.h"
+ "${CURL_DIR}/lib/memdebug.c"
+ "${CURL_DIR}/lib/progress.c"
+ "${CURL_DIR}/lib/curl_sha256.h"
+ "${CURL_DIR}/lib/inet_pton.h"
+ "${CURL_DIR}/lib/mqtt.h"
+ "${CURL_DIR}/lib/curl_ntlm_core.c"
+ "${CURL_DIR}/lib/tftp.h"
+ "${CURL_DIR}/lib/slist.h"
+ "${CURL_DIR}/lib/share.h"
+ "${CURL_DIR}/lib/curl_path.c"
+ "${CURL_DIR}/lib/rename.h"
+ "${CURL_DIR}/lib/hostasyn.c"
+ "${CURL_DIR}/lib/pop3.c"
+ "${CURL_DIR}/lib/arpa_telnet.h"
+ "${CURL_DIR}/lib/fopen.h"
+ "${CURL_DIR}/lib/noproxy.c"
+ "${CURL_DIR}/lib/gopher.c"
+ "${CURL_DIR}/lib/rtsp.c"
+ "${CURL_DIR}/lib/curl_gethostname.c"
+ "${CURL_DIR}/lib/curl_des.c"
+ "${CURL_DIR}/lib/curlx.h"
+ "${CURL_DIR}/lib/functypes.h"
+ "${CURL_DIR}/lib/base64.c"
+ "${CURL_DIR}/lib/version_win32.h"
+ "${CURL_DIR}/lib/escape.h"
+ "${CURL_DIR}/lib/setup-win32.h"
+ "${CURL_DIR}/lib/splay.c"
+ "${CURL_DIR}/lib/setup-vms.h"
+ "${CURL_DIR}/lib/hostip.h"
+ "${CURL_DIR}/lib/content_encoding.h"
+ "${CURL_DIR}/lib/http.c"
+ "${CURL_DIR}/lib/config-amigaos.h"
+ "${CURL_DIR}/lib/curl_sspi.c"
+ "${CURL_DIR}/lib/http_chunks.c"
+ "${CURL_DIR}/lib/config-os400.h"
+ "${CURL_DIR}/lib/rand.h"
+ "${CURL_DIR}/lib/dynbuf.h"
+ "${CURL_DIR}/lib/telnet.c"
+ "${CURL_DIR}/lib/amigaos.c"
+ "${CURL_DIR}/lib/asyn.h"
+ "${CURL_DIR}/lib/fileinfo.c"
+ "${CURL_DIR}/lib/timediff.h"
+ "${CURL_DIR}/lib/version.c"
+ "${CURL_DIR}/lib/ldap.c"
+ "${CURL_DIR}/lib/bufref.c"
+ "${CURL_DIR}/lib/curl_sasl.c"
+ "${CURL_DIR}/lib/dynhds.h"
+ "${CURL_DIR}/lib/netrc.c"
+ "${CURL_DIR}/lib/socketpair.c"
+ "${CURL_DIR}/lib/strerror.c"
+ "${CURL_DIR}/lib/curl_multibyte.c"
+ "${CURL_DIR}/lib/http2.h"
+ "${CURL_DIR}/lib/altsvc.c"
+ "${CURL_DIR}/lib/config-riscos.h"
+ "${CURL_DIR}/lib/conncache.c"
+ "${CURL_DIR}/lib/curl_memrchr.c"
+ "${CURL_DIR}/lib/smb.c"
+ "${CURL_DIR}/lib/transfer.h"
+ "${CURL_DIR}/lib/sha256.c"
+ "${CURL_DIR}/lib/system_win32.h"
+ "${CURL_DIR}/lib/connect.c"
+ "${CURL_DIR}/lib/ws.c"
+ "${CURL_DIR}/lib/ftp.c"
+ "${CURL_DIR}/lib/strtoofft.c"
+ "${CURL_DIR}/lib/md5.c"
+ "${CURL_DIR}/lib/vauth/krb5_sspi.c"
+ "${CURL_DIR}/lib/vauth/spnego_sspi.c"
+ "${CURL_DIR}/lib/vauth/ntlm.c"
+ "${CURL_DIR}/lib/vauth/gsasl.c"
+ "${CURL_DIR}/lib/vauth/spnego_gssapi.c"
+ "${CURL_DIR}/lib/vauth/digest.h"
+ "${CURL_DIR}/lib/vauth/ntlm_sspi.c"
+ "${CURL_DIR}/lib/vauth/vauth.c"
+ "${CURL_DIR}/lib/vauth/oauth2.c"
+ "${CURL_DIR}/lib/vauth/ntlm.h"
+ "${CURL_DIR}/lib/vauth/cram.c"
+ "${CURL_DIR}/lib/vauth/cleartext.c"
+ "${CURL_DIR}/lib/vauth/krb5_gssapi.c"
+ "${CURL_DIR}/lib/vauth/digest.c"
+ "${CURL_DIR}/lib/vauth/digest_sspi.c"
+ "${CURL_DIR}/lib/vauth/vauth.h"
+ "${CURL_DIR}/lib/file.c"
+ "${CURL_DIR}/lib/cfilters.h"
+ "${CURL_DIR}/lib/http_digest.c"
+ "${CURL_DIR}/lib/cf-haproxy.h"
+ "${CURL_DIR}/lib/asyn-thread.c"
+ "${CURL_DIR}/lib/cf-h1-proxy.c"
+ "${CURL_DIR}/lib/curl_md5.h"
+ "${CURL_DIR}/lib/urlapi-int.h"
+ "${CURL_DIR}/lib/hsts.c"
+ "${CURL_DIR}/lib/vtls/cipher_suite.c"
+ "${CURL_DIR}/lib/vtls/cipher_suite.h"
+ "${CURL_DIR}/lib/vtls/mbedtls.c"
+ "${CURL_DIR}/lib/vtls/gtls.c"
+ "${CURL_DIR}/lib/vtls/bearssl.c"
+ "${CURL_DIR}/lib/vtls/vtls.h"
+ "${CURL_DIR}/lib/vtls/hostcheck.c"
+ "${CURL_DIR}/lib/vtls/rustls.c"
+ "${CURL_DIR}/lib/vtls/wolfssl.h"
+ "${CURL_DIR}/lib/vtls/schannel.c"
+ "${CURL_DIR}/lib/vtls/openssl.h"
+ "${CURL_DIR}/lib/vtls/keylog.h"
+ "${CURL_DIR}/lib/vtls/sectransp.c"
+ "${CURL_DIR}/lib/vtls/schannel_verify.c"
+ "${CURL_DIR}/lib/vtls/x509asn1.h"
+ "${CURL_DIR}/lib/vtls/mbedtls_threadlock.h"
+ "${CURL_DIR}/lib/vtls/vtls.c"
+ "${CURL_DIR}/lib/vtls/bearssl.h"
+ "${CURL_DIR}/lib/vtls/hostcheck.h"
+ "${CURL_DIR}/lib/vtls/gtls.h"
+ "${CURL_DIR}/lib/vtls/mbedtls.h"
+ "${CURL_DIR}/lib/vtls/vtls_int.h"
+ "${CURL_DIR}/lib/vtls/schannel_int.h"
+ "${CURL_DIR}/lib/vtls/rustls.h"
+ "${CURL_DIR}/lib/vtls/keylog.c"
+ "${CURL_DIR}/lib/vtls/openssl.c"
+ "${CURL_DIR}/lib/vtls/wolfssl.c"
+ "${CURL_DIR}/lib/vtls/schannel.h"
+ "${CURL_DIR}/lib/vtls/mbedtls_threadlock.c"
+ "${CURL_DIR}/lib/vtls/x509asn1.c"
+ "${CURL_DIR}/lib/vtls/sectransp.h"
+ "${CURL_DIR}/lib/parsedate.h"
+ "${CURL_DIR}/lib/curl_trc.h"
+ "${CURL_DIR}/lib/warnless.h"
+ "${CURL_DIR}/lib/socks.h"
+ "${CURL_DIR}/lib/vssh/libssh.c"
+ "${CURL_DIR}/lib/vssh/libssh2.c"
+ "${CURL_DIR}/lib/vssh/ssh.h"
+ "${CURL_DIR}/lib/vssh/wolfssh.c"
+ "${CURL_DIR}/lib/asyn-ares.c"
+ "${CURL_DIR}/lib/imap.c"
+ "${CURL_DIR}/lib/config-dos.h"
+ "${CURL_DIR}/lib/headers.c"
+ "${CURL_DIR}/lib/macos.c"
+ "${CURL_DIR}/lib/cookie.c"
+ "${CURL_DIR}/lib/curl_krb5.h"
+ "${CURL_DIR}/lib/hostip6.c"
+ "${CURL_DIR}/lib/sendf.c"
+ "${CURL_DIR}/lib/ftplistparser.c"
+ "${CURL_DIR}/lib/http_ntlm.c"
+ "${CURL_DIR}/lib/http_proxy.h"
+ "${CURL_DIR}/lib/bufq.h"
+ "${CURL_DIR}/lib/hash.h"
+ "${CURL_DIR}/lib/config-mac.h"
+ "${CURL_DIR}/lib/setopt.c"
+ "${CURL_DIR}/lib/easy_lock.h"
+ "${CURL_DIR}/lib/curl_base64.h"
+ "${CURL_DIR}/lib/sigpipe.h"
+ "${CURL_DIR}/lib/getinfo.c"
+ "${CURL_DIR}/lib/speedcheck.c"
+ "${CURL_DIR}/lib/http1.h"
+ "${CURL_DIR}/lib/inet_ntop.c"
+ "${CURL_DIR}/lib/curl_rtmp.h"
+ "${CURL_DIR}/lib/curl_gssapi.c"
+ "${CURL_DIR}/lib/curl_fnmatch.c"
+ "${CURL_DIR}/lib/select.h"
+ "${CURL_DIR}/lib/nonblock.h"
+ "${CURL_DIR}/lib/curl_sha512_256.c"
+ "${CURL_DIR}/lib/curl_sha512_256.h"
+ "${CURL_DIR}/lib/cw-out.c"
+ "${CURL_DIR}/lib/cw-out.h"
+ "${CURL_DIR}/lib/request.c"
+ "${CURL_DIR}/lib/request.h"
+ "${CURL_DIR}/lib/vquic/curl_osslq.c"
+ "${CURL_DIR}/lib/vquic/curl_osslq.h"
+ "${CURL_DIR}/lib/vquic/vquic-tls.c"
+ "${CURL_DIR}/lib/vquic/vquic-tls.h")
+
+ # General options
+ target_compile_definitions(curl PRIVATE BUILDING_LIBCURL)
+ target_compile_definitions(curl PRIVATE UNICODE)
+ target_compile_definitions(curl PRIVATE _UNICODE)
+ target_compile_definitions(curl PRIVATE HTTP_ONLY)
+ target_compile_definitions(curl PRIVATE ENABLE_IPV6)
+ target_compile_definitions(curl PRIVATE USE_BEARSSL)
+ target_compile_definitions(curl PRIVATE SIZEOF_CURL_OFF_T=8)
+ # To support HTTP compression
+ target_compile_definitions(curl PRIVATE HAVE_LIBZ)
+ if(NOT BUILD_SHARED_LIBS)
+ target_compile_definitions(curl PUBLIC CURL_STATICLIB)
+ endif()
+
+ # Platform specific options
+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ target_compile_definitions(curl PRIVATE OS="Linux")
+ target_compile_definitions(curl PRIVATE CURL_CA_BUNDLE="/etc/ssl/certs/ca-certificates.crt")
+ target_compile_definitions(curl PRIVATE CURL_CA_PATH="/etc/ssl/certs")
+ target_compile_definitions(curl PRIVATE HAVE_SYS_TIME_H)
+ target_compile_definitions(curl PRIVATE HAVE_LONGLONG)
+ target_compile_definitions(curl PRIVATE HAVE_RECV)
+ target_compile_definitions(curl PRIVATE HAVE_SEND)
+ target_compile_definitions(curl PRIVATE HAVE_SOCKET)
+ target_compile_definitions(curl PRIVATE HAVE_NETDB_H)
+ target_compile_definitions(curl PRIVATE HAVE_ARPA_INET_H)
+ target_compile_definitions(curl PRIVATE HAVE_SNPRINTF)
+ target_compile_definitions(curl PRIVATE HAVE_UNISTD_H)
+ target_compile_definitions(curl PRIVATE HAVE_SYS_STAT_H)
+ target_compile_definitions(curl PRIVATE HAVE_FCNTL_H)
+ target_compile_definitions(curl PRIVATE HAVE_SELECT)
+ target_compile_definitions(curl PRIVATE HAVE_POLL)
+ target_compile_definitions(curl PRIVATE HAVE_FCNTL_O_NONBLOCK)
+ target_compile_definitions(curl PRIVATE HAVE_STRUCT_TIMEVAL)
+ target_compile_definitions(curl PRIVATE HAVE_GETSOCKNAME)
+ # POSIX.1-2008
+ target_compile_definitions(curl PRIVATE _POSIX_C_SOURCE=200809L)
+ elseif(APPLE)
+ target_compile_definitions(curl PRIVATE OS="Darwin")
+ target_compile_definitions(curl PRIVATE CURL_CA_BUNDLE="/etc/ssl/cert.pem")
+ target_compile_definitions(curl PRIVATE CURL_CA_PATH="/etc/ssl/certs")
+ target_compile_definitions(curl PRIVATE HAVE_RECV)
+ target_compile_definitions(curl PRIVATE HAVE_SEND)
+ target_compile_definitions(curl PRIVATE HAVE_SOCKET)
+ target_compile_definitions(curl PRIVATE HAVE_NETDB_H)
+ target_compile_definitions(curl PRIVATE HAVE_SNPRINTF)
+ target_compile_definitions(curl PRIVATE HAVE_UNISTD_H)
+ target_compile_definitions(curl PRIVATE HAVE_SYS_STAT_H)
+ target_compile_definitions(curl PRIVATE HAVE_FCNTL_H)
+ target_compile_definitions(curl PRIVATE HAVE_SELECT)
+ target_compile_definitions(curl PRIVATE HAVE_POLL)
+ target_compile_definitions(curl PRIVATE HAVE_FCNTL_O_NONBLOCK)
+ target_compile_definitions(curl PRIVATE HAVE_STRUCT_TIMEVAL)
+ target_compile_definitions(curl PRIVATE HAVE_GETSOCKNAME)
+ elseif(WIN32)
+ target_compile_definitions(curl PRIVATE OS="Windows")
+ endif()
+
+ target_include_directories(curl PRIVATE "${CURL_DIR}/lib")
+
+ target_link_libraries(curl PRIVATE ZLIB::ZLIB)
+ target_link_libraries(curl PRIVATE BearSSL::BearSSL)
+ if(APPLE)
+ target_link_libraries(curl PRIVATE "-framework Foundation")
+ target_link_libraries(curl PRIVATE "-framework SystemConfiguration")
+ elseif(WIN32)
+ target_link_libraries(curl PRIVATE ws2_32)
+ target_link_libraries(curl PRIVATE Crypt32.lib)
+ endif()
+
+ target_include_directories(curl PUBLIC
+ "$"
+ "$")
+
+ add_library(CURL::libcurl ALIAS curl)
+
+ set_target_properties(curl
+ PROPERTIES
+ OUTPUT_NAME curl
+ PUBLIC_HEADER "${CURL_PUBLIC_HEADER}"
+ PRIVATE_HEADER "${CURL_PRIVATE_HEADERS}"
+ C_VISIBILITY_PRESET "default"
+ C_VISIBILITY_INLINES_HIDDEN FALSE
+ EXPORT_NAME curl)
+
+ include(GNUInstallDirs)
+ install(TARGETS curl
+ EXPORT curl
+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/curl"
+ COMPONENT sourcemeta_hydra_dev
+ PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/curl"
+ COMPONENT sourcemeta_hydra_dev
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ COMPONENT sourcemeta_hydra
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra
+ NAMELINK_COMPONENT sourcemeta_hydra_dev
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra_dev)
+ install(EXPORT curl
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/curl"
+ COMPONENT sourcemeta_hydra_dev)
+
+ # TODO: Why does `find_dependency(ZLIB)` fail to locate ZLIB
+ # if even `CMAKE_PREFIX_PATH` is correct?
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/curl-config.cmake
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/../zlib/zlib-config.cmake\")\n"
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/curl.cmake\")\n"
+ "check_required_components(\"curl\")\n")
+ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/curl-config.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/curl"
+ COMPONENT sourcemeta_hydra_dev)
+
+ set(CURL_FOUND ON)
+endif()
diff --git a/vendor/hydra/cmake/FindZLIB.cmake b/vendor/hydra/cmake/FindZLIB.cmake
new file mode 100644
index 00000000..d63b93e1
--- /dev/null
+++ b/vendor/hydra/cmake/FindZLIB.cmake
@@ -0,0 +1,83 @@
+if(NOT ZLIB_FOUND)
+ set(Z_HAVE_UNISTD_H ON)
+ configure_file("${PROJECT_SOURCE_DIR}/vendor/zlib/zconf.h.cmakein"
+ "${CMAKE_CURRENT_BINARY_DIR}/zlib/zconf.h" @ONLY)
+
+ set(ZLIB_DIR "${PROJECT_SOURCE_DIR}/vendor/zlib")
+ set(ZLIB_PUBLIC_HEADER "${ZLIB_DIR}/zlib.h")
+ set(ZLIB_PRIVATE_HEADERS "${CMAKE_CURRENT_BINARY_DIR}/zlib/zconf.h")
+
+ add_library(zlib
+ "${ZLIB_PUBLIC_HEADER}" ${ZLIB_PRIVATE_HEADERS}
+ "${ZLIB_DIR}/adler32.c"
+ "${ZLIB_DIR}/compress.c"
+ "${ZLIB_DIR}/crc32.c"
+ "${ZLIB_DIR}/crc32.h"
+ "${ZLIB_DIR}/deflate.c"
+ "${ZLIB_DIR}/deflate.h"
+ "${ZLIB_DIR}/gzclose.c"
+ "${ZLIB_DIR}/gzguts.h"
+ "${ZLIB_DIR}/gzlib.c"
+ "${ZLIB_DIR}/gzread.c"
+ "${ZLIB_DIR}/gzwrite.c"
+ "${ZLIB_DIR}/infback.c"
+ "${ZLIB_DIR}/inffast.c"
+ "${ZLIB_DIR}/inffast.h"
+ "${ZLIB_DIR}/inffixed.h"
+ "${ZLIB_DIR}/inflate.c"
+ "${ZLIB_DIR}/inflate.h"
+ "${ZLIB_DIR}/inftrees.c"
+ "${ZLIB_DIR}/inftrees.h"
+ "${ZLIB_DIR}/trees.c"
+ "${ZLIB_DIR}/trees.h"
+ "${ZLIB_DIR}/uncompr.c"
+ "${ZLIB_DIR}/zutil.c"
+ "${ZLIB_DIR}/zutil.h")
+
+ target_compile_definitions(zlib PUBLIC NO_FSEEKO)
+ target_compile_definitions(zlib PUBLIC _LARGEFILE64_SOURCE=1)
+
+ target_include_directories(zlib PUBLIC
+ "$"
+ "$")
+
+ add_library(ZLIB::ZLIB ALIAS zlib)
+
+ set_target_properties(zlib
+ PROPERTIES
+ OUTPUT_NAME zlib
+ PUBLIC_HEADER "${ZLIB_PUBLIC_HEADER}"
+ PRIVATE_HEADER "${ZLIB_PRIVATE_HEADERS}"
+ C_VISIBILITY_PRESET "default"
+ C_VISIBILITY_INLINES_HIDDEN FALSE
+ WINDOWS_EXPORT_ALL_SYMBOLS TRUE
+ EXPORT_NAME zlib)
+
+ include(GNUInstallDirs)
+ install(TARGETS zlib
+ EXPORT zlib
+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+ COMPONENT sourcemeta_hydra_dev
+ PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+ COMPONENT sourcemeta_hydra_dev
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ COMPONENT sourcemeta_hydra
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra
+ NAMELINK_COMPONENT sourcemeta_hydra_dev
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra_dev)
+ install(EXPORT zlib
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zlib"
+ COMPONENT sourcemeta_hydra_dev)
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/zlib-config.cmake
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/zlib.cmake\")\n"
+ "check_required_components(\"zlib\")\n")
+ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/zlib-config.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/zlib"
+ COMPONENT sourcemeta_hydra_dev)
+
+ set(ZLIB_FOUND ON)
+endif()
diff --git a/vendor/hydra/cmake/FinduSockets.cmake b/vendor/hydra/cmake/FinduSockets.cmake
new file mode 100644
index 00000000..160301c0
--- /dev/null
+++ b/vendor/hydra/cmake/FinduSockets.cmake
@@ -0,0 +1,84 @@
+if(NOT uSockets_FOUND)
+ set(USOCKETS_DIR "${PROJECT_SOURCE_DIR}/vendor/uwebsockets/uSockets")
+ set(USOCKETS_PUBLIC_HEADER "${USOCKETS_DIR}/src/libusockets.h")
+
+ add_library(usockets
+ "${USOCKETS_PUBLIC_HEADER}"
+ "${USOCKETS_DIR}/src/internal/networking/bsd.h"
+ "${USOCKETS_DIR}/src/bsd.c"
+ "${USOCKETS_DIR}/src/context.c"
+ "${USOCKETS_DIR}/src/loop.c"
+ "${USOCKETS_DIR}/src/socket.c"
+ "${USOCKETS_DIR}/src/udp.c"
+ "${USOCKETS_DIR}/src/crypto/openssl.c"
+ "${USOCKETS_DIR}/src/crypto/sni_tree.cpp"
+ "${USOCKETS_DIR}/src/quic.c"
+ "${USOCKETS_DIR}/src/quic.h"
+ "${USOCKETS_DIR}/src/internal/eventing/epoll_kqueue.h"
+ "${USOCKETS_DIR}/src/eventing/epoll_kqueue.c"
+ "${USOCKETS_DIR}/src/io_uring/internal.h"
+ "${USOCKETS_DIR}/src/io_uring/io_context.c"
+ "${USOCKETS_DIR}/src/io_uring/io_loop.c"
+ "${USOCKETS_DIR}/src/io_uring/io_socket.c"
+ "${USOCKETS_DIR}/src/internal/eventing/gcd.h"
+ "${USOCKETS_DIR}/src/eventing/gcd.c"
+ "${USOCKETS_DIR}/src/internal/eventing/libuv.h"
+ "${USOCKETS_DIR}/src/eventing/libuv.c"
+ "${USOCKETS_DIR}/src/internal/eventing/asio.h")
+
+ target_compile_definitions(usockets PUBLIC LIBUS_NO_SSL)
+
+ # Configure the event loop
+ if(WIN32)
+ # TODO: Make it work on Windows. Main challenge is that uSockets
+ # relies on libuv for that platform.
+ message(FATAL_ERROR "Hydra does not support uSockets on Windows yet")
+ elseif(APPLE)
+ target_compile_definitions(usockets PUBLIC LIBUS_USE_KQUEUE)
+ else()
+ target_compile_definitions(usockets PUBLIC LIBUS_USE_EPOLL)
+ endif()
+
+ target_include_directories(usockets PUBLIC
+ "$"
+ "$")
+
+ add_library(uNetworking::uSockets ALIAS usockets)
+
+ set_target_properties(usockets
+ PROPERTIES
+ OUTPUT_NAME usockets
+ PUBLIC_HEADER "${USOCKETS_PUBLIC_HEADER}"
+ C_VISIBILITY_PRESET "default"
+ C_VISIBILITY_INLINES_HIDDEN FALSE
+ WINDOWS_EXPORT_ALL_SYMBOLS TRUE
+ EXPORT_NAME usockets)
+
+ include(GNUInstallDirs)
+ install(TARGETS usockets
+ EXPORT usockets
+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+ COMPONENT sourcemeta_hydra_dev
+ PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
+ COMPONENT sourcemeta_hydra_dev
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ COMPONENT sourcemeta_hydra
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra
+ NAMELINK_COMPONENT sourcemeta_hydra_dev
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra_dev)
+ install(EXPORT usockets
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/usockets"
+ COMPONENT sourcemeta_hydra_dev)
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/usockets-config.cmake
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/usockets.cmake\")\n"
+ "check_required_components(\"usockets\")\n")
+ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/usockets-config.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/usockets"
+ COMPONENT sourcemeta_hydra_dev)
+
+ set(uSockets_FOUND ON)
+endif()
diff --git a/vendor/hydra/cmake/FinduWebSockets.cmake b/vendor/hydra/cmake/FinduWebSockets.cmake
new file mode 100644
index 00000000..a28695a2
--- /dev/null
+++ b/vendor/hydra/cmake/FinduWebSockets.cmake
@@ -0,0 +1,92 @@
+if(NOT uWebSockets_FOUND)
+ set(UWEBSOCKETS_DIR "${PROJECT_SOURCE_DIR}/vendor/uwebsockets")
+ set(UWEBSOCKETS_PUBLIC_HEADER "${UWEBSOCKETS_DIR}/src/App.h")
+ set(UWEBSOCKETS_PRIVATE_HEADERS
+ "${UWEBSOCKETS_DIR}/src/LocalCluster.h"
+ "${UWEBSOCKETS_DIR}/src/AsyncSocket.h"
+ "${UWEBSOCKETS_DIR}/src/AsyncSocketData.h"
+ "${UWEBSOCKETS_DIR}/src/BloomFilter.h"
+ "${UWEBSOCKETS_DIR}/src/ChunkedEncoding.h"
+ "${UWEBSOCKETS_DIR}/src/ClientApp.h"
+ "${UWEBSOCKETS_DIR}/src/Http3App.h"
+ "${UWEBSOCKETS_DIR}/src/Http3Context.h"
+ "${UWEBSOCKETS_DIR}/src/Http3ContextData.h"
+ "${UWEBSOCKETS_DIR}/src/Http3Request.h"
+ "${UWEBSOCKETS_DIR}/src/Http3Response.h"
+ "${UWEBSOCKETS_DIR}/src/Http3ResponseData.h"
+ "${UWEBSOCKETS_DIR}/src/HttpContext.h"
+ "${UWEBSOCKETS_DIR}/src/HttpContextData.h"
+ "${UWEBSOCKETS_DIR}/src/HttpErrors.h"
+ "${UWEBSOCKETS_DIR}/src/HttpParser.h"
+ "${UWEBSOCKETS_DIR}/src/HttpResponse.h"
+ "${UWEBSOCKETS_DIR}/src/HttpResponseData.h"
+ "${UWEBSOCKETS_DIR}/src/HttpRouter.h"
+ "${UWEBSOCKETS_DIR}/src/Loop.h"
+ "${UWEBSOCKETS_DIR}/src/LoopData.h"
+ "${UWEBSOCKETS_DIR}/src/MessageParser.h"
+ "${UWEBSOCKETS_DIR}/src/MoveOnlyFunction.h"
+ "${UWEBSOCKETS_DIR}/src/Multipart.h"
+ "${UWEBSOCKETS_DIR}/src/PerMessageDeflate.h"
+ "${UWEBSOCKETS_DIR}/src/ProxyParser.h"
+ "${UWEBSOCKETS_DIR}/src/QueryParser.h"
+ "${UWEBSOCKETS_DIR}/src/TopicTree.h"
+ "${UWEBSOCKETS_DIR}/src/Utilities.h"
+ "${UWEBSOCKETS_DIR}/src/WebSocket.h"
+ "${UWEBSOCKETS_DIR}/src/WebSocketContext.h"
+ "${UWEBSOCKETS_DIR}/src/WebSocketContextData.h"
+ "${UWEBSOCKETS_DIR}/src/WebSocketData.h"
+ "${UWEBSOCKETS_DIR}/src/WebSocketExtensions.h"
+ "${UWEBSOCKETS_DIR}/src/WebSocketHandshake.h"
+ "${UWEBSOCKETS_DIR}/src/WebSocketProtocol.h")
+
+ add_library(uwebsockets INTERFACE
+ "${UWEBSOCKETS_PUBLIC_HEADER}" ${UWEBSOCKETS_PRIVATE_HEADERS})
+
+ # Avoid "uWebSockets: " default header
+ target_compile_definitions(uwebsockets
+ INTERFACE UWS_HTTPRESPONSE_NO_WRITEMARK)
+
+ target_link_libraries(uwebsockets INTERFACE ZLIB::ZLIB)
+ target_link_libraries(uwebsockets INTERFACE uNetworking::uSockets)
+
+ target_include_directories(usockets PUBLIC
+ "$"
+ "$")
+
+ add_library(uNetworking::uWebSockets ALIAS uwebsockets)
+
+ set_target_properties(uwebsockets
+ PROPERTIES
+ OUTPUT_NAME uwebsockets
+ PUBLIC_HEADER "${UWEBSOCKETS_PUBLIC_HEADER}"
+ PRIVATE_HEADER "${UWEBSOCKETS_PRIVATE_HEADERS}"
+ EXPORT_NAME uwebsockets)
+
+ include(GNUInstallDirs)
+ install(TARGETS uwebsockets
+ EXPORT uwebsockets
+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/uwebsockets/src"
+ COMPONENT sourcemeta_hydra_dev
+ PRIVATE_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/uwebsockets/src"
+ COMPONENT sourcemeta_hydra_dev
+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ COMPONENT sourcemeta_hydra
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra
+ NAMELINK_COMPONENT sourcemeta_hydra_dev
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT sourcemeta_hydra_dev)
+ install(EXPORT uwebsockets
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/uwebsockets"
+ COMPONENT sourcemeta_hydra_dev)
+
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/uwebsockets-config.cmake
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/uwebsockets.cmake\")\n"
+ "check_required_components(\"uwebsockets\")\n")
+ install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/uwebsockets-config.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/uwebsockets"
+ COMPONENT sourcemeta_hydra_dev)
+
+ set(uWebSockets_FOUND ON)
+endif()
diff --git a/vendor/hydra/config.cmake.in b/vendor/hydra/config.cmake.in
new file mode 100644
index 00000000..3f2b3e9c
--- /dev/null
+++ b/vendor/hydra/config.cmake.in
@@ -0,0 +1,58 @@
+@PACKAGE_INIT@
+
+# Support both casing styles
+list(APPEND HYDRA_COMPONENTS ${Hydra_FIND_COMPONENTS})
+list(APPEND HYDRA_COMPONENTS ${hydra_FIND_COMPONENTS})
+if(NOT HYDRA_COMPONENTS)
+ list(APPEND HYDRA_COMPONENTS httpclient)
+ # TODO: Make it work on Windows. Main challenge is that uSockets
+ # relies on libuv for that platform.
+ if(NOT WIN32)
+ list(APPEND HYDRA_COMPONENTS httpserver)
+ endif()
+ list(APPEND HYDRA_COMPONENTS bucket)
+endif()
+
+include(CMakeFindDependencyMacro)
+
+# GCC does not allow the use of std::promise, std::future
+# without compiling with pthreads support.
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+ find_dependency(Threads)
+endif()
+
+foreach(component ${HYDRA_COMPONENTS})
+ if(component STREQUAL "httpclient")
+ include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_hydra_http.cmake")
+ find_dependency(ZLIB)
+ find_dependency(BearSSL)
+ find_dependency(CURL)
+ include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_hydra_httpclient.cmake")
+ elseif(component STREQUAL "httpserver")
+ if(WIN32)
+ # TODO: Make it work on Windows. Main challenge is that uSockets
+ # relies on libuv for that platform.
+ message(FATAL_ERROR "Hydra does not support the HTTP Server module on Windows yet")
+ endif()
+
+ include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_hydra_http.cmake")
+ find_dependency(uSockets)
+ find_dependency(uWebSockets)
+ find_dependency(JSONToolkit COMPONENTS json)
+ include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_hydra_httpserver.cmake")
+ elseif(component STREQUAL "bucket")
+ include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_hydra_http.cmake")
+ find_dependency(ZLIB)
+ find_dependency(BearSSL)
+ find_dependency(CURL)
+ include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_hydra_httpclient.cmake")
+ find_dependency(JSONToolkit COMPONENTS json uri)
+ include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_hydra_bucket.cmake")
+ else()
+ message(FATAL_ERROR "Unknown Hydra component: ${component}")
+ endif()
+endforeach()
+
+check_required_components("@PROJECT_NAME@")
diff --git a/vendor/hydra/src/bucket/CMakeLists.txt b/vendor/hydra/src/bucket/CMakeLists.txt
new file mode 100644
index 00000000..8c1d4485
--- /dev/null
+++ b/vendor/hydra/src/bucket/CMakeLists.txt
@@ -0,0 +1,15 @@
+noa_library(NAMESPACE sourcemeta PROJECT hydra NAME bucket
+ FOLDER "Hydra/Bucket"
+ PRIVATE_HEADERS cache.h cache_policy.h error.h response.h aws_sigv4.h
+ SOURCES bucket.cc bucket_error.cc aws_sigv4.cc)
+
+if(HYDRA_INSTALL)
+ noa_library_install(NAMESPACE sourcemeta PROJECT hydra NAME bucket)
+endif()
+
+target_link_libraries(sourcemeta_hydra_bucket PUBLIC sourcemeta::jsontoolkit::json)
+target_link_libraries(sourcemeta_hydra_bucket PUBLIC sourcemeta::jsontoolkit::uri)
+target_link_libraries(sourcemeta_hydra_bucket PUBLIC sourcemeta::hydra::http)
+target_link_libraries(sourcemeta_hydra_bucket PRIVATE sourcemeta::hydra::httpclient)
+target_link_libraries(sourcemeta_hydra_bucket PRIVATE BearSSL::BearSSL)
+sourcemeta_hydra_add_compile_options(sourcemeta_hydra_bucket)
diff --git a/vendor/hydra/src/bucket/aws_sigv4.cc b/vendor/hydra/src/bucket/aws_sigv4.cc
new file mode 100644
index 00000000..0b825e74
--- /dev/null
+++ b/vendor/hydra/src/bucket/aws_sigv4.cc
@@ -0,0 +1,245 @@
+#include
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wimplicit-int-conversion"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion"
+#elif defined(_MSC_VER)
+#pragma warning(disable : 4244 4267)
+#endif
+extern "C" {
+#include
+}
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
+#elif defined(_MSC_VER)
+#pragma warning(default : 4244 4267)
+#endif
+
+#include // assert
+#include // std::time_t, std::tm, std::gmtime
+#include // std::setfill, std::setw, std::put_time
+#include // std::hex, std::ios_base
+#include // std::ostringstream
+#include // std::runtime_error
+#include // std::move
+
+namespace sourcemeta::hydra {
+
+auto aws_sigv4_sha256(std::string_view input, std::ostream &output) -> void {
+ br_sha256_context context;
+ br_sha256_init(&context);
+ br_sha256_update(&context, input.data(), input.size());
+ unsigned char hash[br_sha256_SIZE];
+ br_sha256_out(&context, hash);
+ std::string_view buffer{reinterpret_cast(hash), br_sha256_SIZE};
+ output << std::hex << std::setfill('0');
+ for (const auto character : buffer) {
+ output << std::setw(2)
+ << static_cast(static_cast(character));
+ }
+
+ output.unsetf(std::ios_base::hex);
+}
+
+auto aws_sigv4_hmac_sha256(std::string_view secret, std::string_view value,
+ std::ostream &output) -> void {
+ br_hmac_key_context key_context;
+ br_hmac_key_init(&key_context, &br_sha256_vtable, secret.data(),
+ secret.size());
+ br_hmac_context context;
+ br_hmac_init(&context, &key_context, 0);
+ br_hmac_update(&context, value.data(), value.size());
+ unsigned char hash[br_sha256_SIZE];
+ br_hmac_out(&context, hash);
+ std::string_view buffer{reinterpret_cast(hash), br_sha256_SIZE};
+ output << buffer;
+}
+
+template
+static auto base64_map_character(const CharT input, const std::size_t position,
+ const std::size_t limit) -> CharT {
+ static const CharT BASE64_DICTIONARY[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ return position > limit ? '='
+ : BASE64_DICTIONARY[static_cast(input)];
+}
+
+// Adapted from https://stackoverflow.com/a/31322410/1641422
+auto aws_sigv4_base64(std::string_view input, std::ostream &output) -> void {
+ using CharT = std::ostream::char_type;
+ const auto remainder{input.size() % 3};
+ const std::size_t next_multiple_of_3{
+ remainder == 0 ? input.size() : input.size() + (3 - remainder)};
+ const std::size_t total_size{4 * (next_multiple_of_3 / 3)};
+ const std::size_t limit{total_size - (next_multiple_of_3 - input.size()) - 1};
+ std::size_t cursor = 0;
+ for (std::size_t index = 0; index < total_size / 4; index++) {
+ // Read a group of three bytes
+ CharT triplet[3];
+ triplet[0] = ((index * 3) + 0 < input.size()) ? input[(index * 3) + 0] : 0;
+ triplet[1] = ((index * 3) + 1 < input.size()) ? input[(index * 3) + 1] : 0;
+ triplet[2] = ((index * 3) + 2 < input.size()) ? input[(index * 3) + 2] : 0;
+
+ // Transform into four base 64 characters
+ CharT quad[4];
+ quad[0] = static_cast((triplet[0] & 0xfc) >> 2);
+ quad[1] = static_cast(((triplet[0] & 0x03) << 4) +
+ ((triplet[1] & 0xf0) >> 4));
+ quad[2] = static_cast(((triplet[1] & 0x0f) << 2) +
+ ((triplet[2] & 0xc0) >> 6));
+ quad[3] = static_cast(((triplet[2] & 0x3f) << 0));
+
+ // Write resulting characters
+ output.put(base64_map_character(quad[0], cursor, limit));
+ cursor += 1;
+ output.put(base64_map_character(quad[1], cursor, limit));
+ cursor += 1;
+ output.put(base64_map_character(quad[2], cursor, limit));
+ cursor += 1;
+ output.put(base64_map_character(quad[3], cursor, limit));
+ cursor += 1;
+ }
+}
+
+static inline auto
+write_date_with_format(const std::chrono::system_clock::time_point time,
+ const char *const format, std::ostream &output) -> void {
+ const std::time_t ctime{std::chrono::system_clock::to_time_t(time)};
+#if defined(_MSC_VER)
+ std::tm buffer;
+ if (gmtime_s(&buffer, &ctime) != 0) {
+ throw std::runtime_error(
+ "Could not convert time point to the desired format");
+ }
+
+ const std::tm *const parts = &buffer;
+#else
+ const std::tm *const parts = std::gmtime(&ctime);
+#endif
+ assert(parts);
+ output << std::put_time(parts, format);
+}
+
+auto aws_sigv4_datastamp(const std::chrono::system_clock::time_point time,
+ std::ostream &output) -> void {
+ write_date_with_format(time, "%Y%m%d", output);
+}
+
+auto aws_sigv4_iso8601(const std::chrono::system_clock::time_point time,
+ std::ostream &output) -> void {
+ write_date_with_format(time, "%Y%m%dT%H%M%SZ", output);
+}
+
+auto aws_sigv4_scope(std::string_view datastamp, std::string_view region,
+ std::ostream &output) -> void {
+ output << datastamp;
+ output << '/';
+ output << region;
+ output << '/';
+ output << "s3";
+ output << '/';
+ output << "aws4_request";
+}
+
+auto aws_sigv4_key(std::string_view secret_key, std::string_view region,
+ std::string_view datastamp) -> std::string {
+ std::ostringstream hmac_date;
+ aws_sigv4_hmac_sha256(std::string{"AWS4"} + std::string{secret_key},
+ datastamp, hmac_date);
+ std::ostringstream hmac_region;
+ aws_sigv4_hmac_sha256(hmac_date.str(), region, hmac_region);
+ std::ostringstream hmac_service;
+ aws_sigv4_hmac_sha256(hmac_region.str(), "s3", hmac_service);
+ std::ostringstream signing_key;
+ aws_sigv4_hmac_sha256(hmac_service.str(), "aws4_request", signing_key);
+ return signing_key.str();
+}
+
+auto aws_sigv4_canonical(const http::Method method, std::string_view host,
+ std::string_view path,
+ std::string_view content_checksum,
+ std::string_view timestamp) -> std::string {
+ std::ostringstream canonical;
+ canonical << method << '\n';
+ canonical << path << '\n';
+ // We don't require query parameters
+ canonical << '\n';
+ canonical << "host:" << host << "\n";
+ canonical << "x-amz-content-sha256:" << content_checksum << "\n";
+ canonical << "x-amz-date:" << timestamp << "\n";
+ canonical << '\n';
+ canonical << "host;x-amz-content-sha256;x-amz-date";
+ canonical << '\n';
+ canonical << content_checksum;
+ return canonical.str();
+}
+
+auto aws_sigv4(const http::Method method,
+ const sourcemeta::jsontoolkit::URI &url,
+ std::string_view access_key, std::string_view secret_key,
+ std::string_view region, std::string &&content_checksum,
+ const std::chrono::system_clock::time_point now)
+ -> std::map {
+ std::ostringstream request_date_iso8601;
+ aws_sigv4_iso8601(now, request_date_iso8601);
+ std::ostringstream request_date_datastamp;
+ aws_sigv4_datastamp(now, request_date_datastamp);
+ // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/host
+ std::ostringstream http_host;
+ assert(url.host().has_value());
+ http_host << url.host().value();
+ if (url.port().has_value()) {
+ http_host << ':' << url.port().value();
+ }
+
+ // Canonical request
+ const auto canonical{sourcemeta::hydra::aws_sigv4_canonical(
+ method, http_host.str(), url.path().value_or("/"), content_checksum,
+ request_date_iso8601.str())};
+
+ // String to sign
+ std::ostringstream string_to_sign;
+ string_to_sign << "AWS4-HMAC-SHA256\n";
+ string_to_sign << request_date_iso8601.str() << '\n';
+ aws_sigv4_scope(request_date_datastamp.str(), region, string_to_sign);
+ string_to_sign << '\n';
+ aws_sigv4_sha256(canonical, string_to_sign);
+
+ // Authorization
+ std::ostringstream authorization;
+ authorization << "AWS4-HMAC-SHA256";
+ authorization << ' ';
+ authorization << "Credential=";
+ authorization << access_key;
+ authorization << '/';
+ aws_sigv4_scope(request_date_datastamp.str(), region, authorization);
+ authorization << ", ";
+ authorization << "SignedHeaders=";
+ authorization << "host;x-amz-content-sha256;x-amz-date";
+ authorization << ", ";
+ authorization << "Signature=";
+
+ const auto signing_key{
+ aws_sigv4_key(secret_key, region, request_date_datastamp.str())};
+ std::ostringstream signature;
+ aws_sigv4_hmac_sha256(signing_key, string_to_sign.str(), signature);
+ authorization << std::hex << std::setfill('0');
+ for (const auto character : signature.str()) {
+ authorization << std::setw(2)
+ << static_cast(
+ static_cast(character));
+ }
+
+ return {{"host", std::move(http_host).str()},
+ {"x-amz-content-sha256", std::move(content_checksum)},
+ {"x-amz-date", std::move(request_date_iso8601).str()},
+ {"authorization", std::move(authorization).str()}};
+}
+
+} // namespace sourcemeta::hydra
diff --git a/vendor/hydra/src/bucket/bucket.cc b/vendor/hydra/src/bucket/bucket.cc
new file mode 100644
index 00000000..ef4b6c7b
--- /dev/null
+++ b/vendor/hydra/src/bucket/bucket.cc
@@ -0,0 +1,159 @@
+#include
+#include
+#include
+
+#include
+
+#include // assert
+#include // std::chrono::system_clock
+#include // std::ostringstream
+#include // std::move
+
+namespace sourcemeta::hydra {
+
+Bucket::Bucket(std::string bucket_url, std::string bucket_region,
+ std::string bucket_access_key, std::string bucket_secret_key,
+ const BucketCachePolicy bucket_cache_policy,
+ const std::uint64_t cache_byte_limit)
+ // clang-format off
+ : cache{std::move(cache_byte_limit)},
+ cache_policy{std::move(bucket_cache_policy)},
+ url{std::move(bucket_url)},
+ region{std::move(bucket_region)},
+ access_key{std::move(bucket_access_key)},
+ secret_key{std::move(bucket_secret_key)} {}
+// clang-format on
+
+auto Bucket::fetch_json(const std::string &key)
+ -> std::future> {
+ std::promise> promise;
+ assert(key.front() == '/');
+
+ const auto cached_result{this->cache.at(key)};
+ if (cached_result.has_value() &&
+ this->cache_policy == BucketCachePolicy::Indefinitely) {
+ promise.set_value(cached_result.value());
+ return promise.get_future();
+ }
+
+ // TODO: Properly build, concat, and canonicalize the string using URI Kit
+ std::ostringstream request_url;
+ request_url << this->url;
+ request_url << key;
+
+ sourcemeta::hydra::http::ClientRequest request{request_url.str()};
+ request.method(sourcemeta::hydra::http::Method::GET);
+ request.capture({"content-type", "etag", "last-modified"});
+
+ if (cached_result.has_value() &&
+ this->cache_policy == BucketCachePolicy::ETag) {
+ request.header("If-None-Match", cached_result.value().etag);
+ }
+
+ // The empty content SHA256
+ static constexpr auto empty_content_checksum{
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"};
+
+ for (auto &&[header, value] :
+ aws_sigv4(request.method(),
+ // TODO: Support constructing a URL given a string_view
+ sourcemeta::jsontoolkit::URI{std::string{request.url()}},
+ this->access_key, this->secret_key, this->region,
+ empty_content_checksum, std::chrono::system_clock::now())) {
+ request.header(std::move(header), std::move(value));
+ }
+
+ sourcemeta::hydra::http::ClientResponse response{request.send().get()};
+
+ const auto status{response.status()};
+ if (status == sourcemeta::hydra::http::Status::NOT_FOUND) {
+ promise.set_value(std::nullopt);
+ return promise.get_future();
+ } else if (status == sourcemeta::hydra::http::Status::NOT_MODIFIED &&
+ cached_result.has_value() &&
+ this->cache_policy == BucketCachePolicy::ETag) {
+ promise.set_value(cached_result.value());
+ return promise.get_future();
+ } else if (status != sourcemeta::hydra::http::Status::OK) {
+ throw BucketError("Failed to fetch JSON from storage");
+ }
+
+ assert(!response.empty());
+ // No S3-compatible bucket lacks these
+ assert(response.header("etag").has_value());
+ assert(response.header("last-modified").has_value());
+
+ ResponseJSON result = {sourcemeta::jsontoolkit::parse(response.body()),
+ response.header("etag").value(),
+ response.header_gmt("last-modified").value(), false};
+
+ this->cache.upsert(key,
+ {result.data, result.etag, result.last_modified, true},
+ result.data.estimated_byte_size());
+
+ promise.set_value(std::move(result));
+ return promise.get_future();
+}
+
+auto Bucket::upsert_json(const std::string &key,
+ const sourcemeta::jsontoolkit::JSON &document)
+ -> std::future {
+ std::promise promise;
+ assert(key.front() == '/');
+
+ // TODO: Properly build, concat, and canonicalize the string using URI Kit
+ std::ostringstream request_url;
+ request_url << this->url;
+ request_url << key;
+
+ sourcemeta::hydra::http::ClientRequest request{request_url.str()};
+ request.method(sourcemeta::hydra::http::Method::PUT);
+ request.header("content-type", "application/json");
+
+ // TODO: Support chunked streaming uploads instead
+ // See https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
+ std::stringstream content;
+ sourcemeta::jsontoolkit::prettify(document, content);
+ std::ostringstream content_checksum;
+ aws_sigv4_sha256(content.str(), content_checksum);
+ request.header("content-length", std::to_string(content.str().size()));
+ request.header("transfer-encoding", "");
+
+ for (auto &&[header, value] :
+ aws_sigv4(request.method(),
+ // TODO: Support constructing a URL given a string_view
+ sourcemeta::jsontoolkit::URI{std::string{request.url()}},
+ this->access_key, this->secret_key, this->region,
+ content_checksum.str(), std::chrono::system_clock::now())) {
+ request.header(std::move(header), std::move(value));
+ }
+
+ sourcemeta::hydra::http::ClientResponse response{request.send(content).get()};
+ const auto status{response.status()};
+ if (status != sourcemeta::hydra::http::Status::OK) {
+ std::ostringstream error;
+ error << "Failed to upsert JSON to storage: " << status;
+ throw BucketError(error.str());
+ }
+
+ return promise.get_future();
+}
+
+auto Bucket::fetch_or_upsert(const std::string &key,
+ std::function
+ callback) -> std::future {
+ std::promise promise;
+ auto maybe_response{this->fetch_json(key).get()};
+ if (maybe_response.has_value()) {
+ promise.set_value(std::move(maybe_response).value());
+ } else {
+ this->upsert_json(key, callback());
+ auto response{this->fetch_json(key).get()};
+ assert(response.has_value());
+ promise.set_value(std::move(response).value());
+ }
+
+ return promise.get_future();
+}
+
+} // namespace sourcemeta::hydra
diff --git a/vendor/hydra/src/bucket/bucket_error.cc b/vendor/hydra/src/bucket/bucket_error.cc
new file mode 100644
index 00000000..002bbc6a
--- /dev/null
+++ b/vendor/hydra/src/bucket/bucket_error.cc
@@ -0,0 +1,13 @@
+#include
+
+#include // std::move
+
+namespace sourcemeta::hydra {
+
+BucketError::BucketError(std::string message) : message_{std::move(message)} {}
+
+auto BucketError::what() const noexcept -> const char * {
+ return this->message_.c_str();
+}
+
+} // namespace sourcemeta::hydra
diff --git a/vendor/hydra/src/bucket/include/sourcemeta/hydra/bucket.h b/vendor/hydra/src/bucket/include/sourcemeta/hydra/bucket.h
new file mode 100644
index 00000000..a51bfbae
--- /dev/null
+++ b/vendor/hydra/src/bucket/include/sourcemeta/hydra/bucket.h
@@ -0,0 +1,195 @@
+#ifndef SOURCEMETA_HYDRA_BUCKET_H
+#define SOURCEMETA_HYDRA_BUCKET_H
+
+#if defined(__Unikraft__)
+#define SOURCEMETA_HYDRA_BUCKET_EXPORT
+#else
+#include "bucket_export.h"
+#endif
+
+/// @defgroup bucket Bucket
+/// @brief This module manages interactions with S3-compatible storage modules
+/// such as S3 itself, Backblaze B2, MinIO, and probably others.
+///
+/// This functionality is included as follows:
+///
+/// ```cpp
+/// #include
+/// ```
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include // std::uint64_t
+#include // std::function
+#include // std::future
+#include // std::optional
+#include // std::string
+
+namespace sourcemeta::hydra {
+
+/// @ingroup bucket
+/// This class is used to interact with S3-compatible HTTP buckets. Keep in mind
+/// that this class is not thread-safe by default. If you are using it in a
+/// concurrent context, make use of `std::mutex` or similar techniques to
+/// control access to it.
+class SOURCEMETA_HYDRA_BUCKET_EXPORT Bucket {
+public:
+ /// Create an instance of this class. This class supports automatically
+ /// caching responses in an LRU fashion based on a byte-size limit. If you set
+ /// the cache byte limit to 0, then caching is effectively disabled.
+ ///
+ /// For example:
+ ///
+ /// ```cpp
+ /// #include
+ ///
+ /// // With caching
+ /// sourcemeta::hydra::Bucket bucket_with_cache{
+ /// // A Backblaze B2 bucket
+ /// "https://s3.us-east-005.backblazeb2.com/my-bucket",
+ /// "us-east-005", "123456789", "ultra-secret",
+ /// // Treat the bucket as immutable and perform aggressive caching
+ /// sourcemeta::hydra::BucketCachePolicy::Indefinitely,
+ /// // Roughly 5 MB
+ /// 5000000};
+ ///
+ /// // Without caching
+ /// sourcemeta::hydra::Bucket bucket_with_cache{
+ /// // A Backblaze B2 bucket
+ /// "https://s3.us-east-005.backblazeb2.com/my-bucket",
+ /// "us-east-005", "123456789", "ultra-secret"};
+ /// ```
+ Bucket(std::string url, std::string region, std::string access_key,
+ std::string secret_key,
+ const BucketCachePolicy cache_policy = BucketCachePolicy::ETag,
+ const std::uint64_t cache_byte_limit = 0);
+
+ // While technically possible, copy semantics are not very useful here
+ // Also, not worth documenting these.
+#if !defined(DOXYGEN)
+ Bucket(const Bucket &other) = delete;
+ auto operator=(const Bucket &other) -> Bucket & = delete;
+#endif
+
+ /// Represents a JSON response from a bucket
+ using ResponseJSON = BucketResponse;
+
+ /// Fetch a JSON document from the given bucket. The key must start with a
+ /// forward slash. For example:
+ ///
+ /// ```cpp
+ /// #include
+ /// #include
+ ///
+ /// #include
+ ///
+ /// sourcemeta::hydra::Bucket bucket{
+ /// // A Backblaze B2 bucket
+ /// "https://s3.us-east-005.backblazeb2.com/my-bucket",
+ /// "us-east-005", "123456789", "ultra-secret",
+ /// // Treat the bucket as immutable and perform aggressive caching
+ /// sourcemeta::hydra::BucketCachePolicy::Indefinitely,
+ /// // Roughly 5 MB
+ /// 5000000};
+ ///
+ /// std::optional response{
+ /// bucket.fetch_json("/foo/bar.json").get()};
+ ///
+ /// if (response.has_value()) {
+ /// sourcemeta::jsontoolkit::prettify(response.value().data, std::cout);
+ /// std::cout << "\n";
+ /// std::cout << "ETag: " << response.value().etag << "\n";
+ /// std::cout << "Last-Modified: "
+ /// << response.value().last_modified << "\n";
+ ///
+ /// if (response.value().cache_hit) {
+ /// std::cout << "This was a cache hit!\n";
+ /// }
+ /// }
+ /// ```
+ ///
+ /// Keep in mind this function does not perform any normalization to the key,
+ /// so to avoid unexpected results (mainly around caching), make sure to pass
+ /// keys in a consistent manner (i.e. casing, etc).
+ auto fetch_json(const std::string &key)
+ -> std::future>;
+
+ /// Upsert a JSON document into the given bucket. The key must start with a
+ /// forward slash. For example:
+ ///
+ /// ```cpp
+ /// #include
+ /// #include
+ ///
+ /// sourcemeta::hydra::Bucket bucket{
+ /// // A Backblaze B2 bucket
+ /// "https://s3.us-east-005.backblazeb2.com/my-bucket",
+ /// "us-east-005", "123456789", "ultra-secret"};
+ ///
+ /// const sourcemeta::jsontoolkit::JSON document =
+ /// sourcemeta::jsontoolkit::parse("{ \"foo\": \"bar\" }");
+ ///
+ /// bucket.upsert_json("/foo/bar.json", document).wait();
+ /// ```
+ auto upsert_json(const std::string &key,
+ const sourcemeta::jsontoolkit::JSON &document)
+ -> std::future;
+
+ /// Upsert a JSON document into the given bucket unless it already exists. If
+ /// so, just return the existing one. The key must start with a forward slash.
+ /// For example:
+ ///
+ /// ```cpp
+ /// #include
+ /// #include
+ ///
+ /// sourcemeta::hydra::Bucket bucket{
+ /// // A Backblaze B2 bucket
+ /// "https://s3.us-east-005.backblazeb2.com/my-bucket",
+ /// "us-east-005", "123456789", "ultra-secret"};
+ ///
+ /// std::optional response{
+ /// bucket.fetch_or_upsert("/foo/bar.json",
+ /// []() -> sourcemeta::jsontoolkit::JSON {
+ /// return sourcemeta::jsontoolkit::parse("{ \"foo\": \"bar\" }");
+ /// }).get()};
+ ///
+ /// if (response.has_value()) {
+ /// sourcemeta::jsontoolkit::prettify(response.value().data, std::cout);
+ /// std::cout << "\n";
+ /// std::cout << "ETag: " << response.value().etag << "\n";
+ /// std::cout << "Last-Modified: "
+ /// << response.value().last_modified << "\n";
+ ///
+ /// if (response.value().cache_hit) {
+ /// std::cout << "This was a cache hit!\n";
+ /// }
+ /// }
+ /// ```
+ auto fetch_or_upsert(const std::string &key,
+ std::function callback)
+ -> std::future;
+
+private:
+#if defined(_MSC_VER)
+#pragma warning(disable : 4251)
+#endif
+ BucketCache cache;
+ const BucketCachePolicy cache_policy;
+ const std::string url;
+ const std::string region;
+ const std::string access_key;
+ const std::string secret_key;
+#if defined(_MSC_VER)
+#pragma warning(default : 4251)
+#endif
+};
+
+} // namespace sourcemeta::hydra
+
+#endif
diff --git a/vendor/hydra/src/bucket/include/sourcemeta/hydra/bucket_aws_sigv4.h b/vendor/hydra/src/bucket/include/sourcemeta/hydra/bucket_aws_sigv4.h
new file mode 100644
index 00000000..bfb28d16
--- /dev/null
+++ b/vendor/hydra/src/bucket/include/sourcemeta/hydra/bucket_aws_sigv4.h
@@ -0,0 +1,70 @@
+#ifndef SOURCEMETA_HYDRA_BUCKET_AWS_SIGV4_H
+#define SOURCEMETA_HYDRA_BUCKET_AWS_SIGV4_H
+
+#if defined(__Unikraft__)
+#define SOURCEMETA_HYDRA_BUCKET_EXPORT
+#else
+#include "bucket_export.h"
+#endif
+
+#include
+#include
+
+#include // std::chrono::system_clock::time_point
+#include