Compare commits

...

164 Commits

Author SHA1 Message Date
yhirose
71ba7e7b1b
Fix #2068 (#2080)
* Fix #2068

* Add unit test
2025-02-20 23:45:21 -05:00
Florian Albrechtskirchinger
ebe7efa1cc
Parallelize testing with/without SSL on Windows & set concurrency group (#2079)
* Parallelize testing with/without SSL on Windows

* Set concurrency group in workflows
2025-02-20 20:57:18 -05:00
Florian Albrechtskirchinger
22d90c29b4
Remove select() and use poll() (#2078)
* Revert "Fix typo in meson.build (#2070)"

This reverts commit 5c0135fa5d.

* Revert "build(meson): automatically use poll or select as needed (#2067)"

This reverts commit 2b5d1eea8d.

* Revert "Make poll() the default (#2065)"

This reverts commit 6e73a63153.

* Remove select() and use poll()
2025-02-20 18:51:35 -05:00
Florian Albrechtskirchinger
b944f942ee
Correct default thread pool size in README.md (#2077) 2025-02-20 12:59:38 -05:00
Florian Albrechtskirchinger
550f728165
Refactor streams: rename is_* to wait_* for clarity (#2069)
- Replace is_readable() with wait_readable() and is_writable() with
  wait_writable() in the Stream interface.
- Implement a new is_readable() function with semantics that more
  closely reflect its name. It returns immediately whether data is
  available for reading, without waiting.
- Update call sites of is_writable(), removing redundant checks.
2025-02-20 12:56:39 -05:00
yhirose
a4b2c61a65
Max timeout test refactoring (#2071)
* Simplify code

* Adjust threshold
2025-02-19 22:19:02 -05:00
Florian Albrechtskirchinger
5c0135fa5d
Fix typo in meson.build (#2070) 2025-02-19 16:20:44 -05:00
Andrea Pappacoda
2b5d1eea8d
build(meson): automatically use poll or select as needed (#2067)
Follow-up to 6e73a63153
2025-02-19 12:47:56 -05:00
yhirose
d274c0abe5 Fix typo 2025-02-18 21:33:32 -05:00
yhirose
dda2e007a0 Fixed documentation about Unix Domain Sockt (#2066) 2025-02-18 11:40:50 -05:00
yhirose
321a86d9f2 Add *.dSYM to Makefile clean 2025-02-18 05:56:22 -05:00
yhirose
ada97046a2 Fix misspelled words 2025-02-18 05:54:22 -05:00
Florian Albrechtskirchinger
6e73a63153
Make poll() the default (#2065)
* Make poll() the default

select() can still be enabled by defining CPPHTTPLIB_USE_SELECT.

* Run tests with select() and poll()
2025-02-18 05:23:23 -05:00
Uros Gaber
cdc223019a
server_certificate_verifier extended to reuse built-in verifier (#2064)
* server_certificate_verifier extended to reuse built-in verifier

* code cleanup and SSLVerifierResponse enum clarification as per @falbrechtskirchinger comment

* cleanup

* clang-format

* change local var verification_status_ declaration to auto

* change local var verification_status_ to verification_status

* clang-format

* clang-format

---------

Co-authored-by: UrosG <uros@ub330.net>
2025-02-17 17:24:41 -05:00
Florian Albrechtskirchinger
574f5ce93e
Add style check to workflow (#2062)
* Add style check to workflow

* Add example files to style check
2025-02-17 12:14:53 -05:00
Florian Albrechtskirchinger
2996cecee0
Fix code inconsistently formatted and re-format (#2063)
* Fix code inconsistently formatted by clang-format

* Run clang-format
2025-02-17 12:14:02 -05:00
Florian Albrechtskirchinger
32bf5c9c09
Simplify SSL shutdown (#2059) 2025-02-16 17:38:41 -05:00
Florian Albrechtskirchinger
735e5930eb
Detect additional CMake build failures (#2058)
Add include_httplib.cc to the main test executable (already done in
Makefile), and add include_windows_h.cc to the main test executable on
Windows to test if including windows.h conflicts with httplib.h.
2025-02-16 15:45:28 -05:00
Florian Albrechtskirchinger
748f47b377
Add workflow_dispatch with Google Test filter and OS selection (#2056)
* Add workflow_dispatch with Google Test filter

Add the workflow_dispatch trigger to the test.yaml workflow. Includes an
input for an optional Google Test filter pattern.

* Add OS selection to workflow_dispatch

* Fix wording
2025-02-16 12:34:28 -05:00
Florian Albrechtskirchinger
4cb8ff9f90
Print timeout exceedance in MaxTimeoutTest (#2060) 2025-02-16 08:43:54 -05:00
Florian Albrechtskirchinger
985cd9f6a2
Fix compilation failures with include <windows.h> (#2057) 2025-02-16 08:39:29 -05:00
Florian Albrechtskirchinger
233f0fb1b8
Refactor setting socket options (#2053)
Add detail::set_socket_opt() and detail::set_socket_opt_time() to avoid
repetition of platform-specific code.
2025-02-14 22:40:24 -05:00
yhirose
03cf43ebaa
Release v0.19.0 2025-02-14 14:42:29 -05:00
yhirose
3c4b96024f Don't run CI twice (on push AND pull request) 2025-02-14 14:19:54 -05:00
yhirose
d74e4a7c9c Removed incomplete API compatibility check scripts. 2025-02-14 14:10:06 -05:00
Andrea Pappacoda
bfa2f735f2
ci: add abidiff workflow (#2054)
This CI workflow checks ABI compatibility between the pushed commit and
the latest tagged release, helping preventing accidental ABI breaks.

Helps with https://github.com/yhirose/cpp-httplib/issues/2043
2025-02-14 14:06:35 -05:00
yhirose
b6ab8435d7 Improve ABI check tool on macOS 2025-02-12 12:49:20 -05:00
yhirose
39a64fb4e7 Fix ABI compatibility tool on macOS 2025-02-11 18:40:39 -05:00
yhirose
d7c14b6f3a Add API compatibility check tool 2025-02-11 17:49:33 -05:00
yhirose
1880693aef Dropped Visual Studio 2015 support 2025-02-11 11:22:46 -05:00
Florian Albrechtskirchinger
dd20342825
Don't run CI twice (on push AND pull request) (#2049) 2025-02-11 06:55:13 -05:00
Brett Profitt
a268d65c4f
Fix check for URI length to prevent incorrect HTTP 414 errors (#2046) 2025-02-10 21:46:38 -05:00
Florian Albrechtskirchinger
b397c768e4
Unify select_read() and select_write() (#2047) 2025-02-10 18:15:19 -05:00
yhirose
8e22a7676a Remome 'global timeout' to 'max timeout' 2025-02-10 18:07:30 -05:00
yhirose
8a7c536ad5
Fix #2034 (#2048)
* Fix #2034

* Fix build error

* Adjust threshold

* Add temporary debug prints

* Adjust threshhold

* Another threshold adjustment for macOS on GitHub Actions CI...

* Performance improvement by avoiding unnecessary chrono access

* More performance improvement to avoid unnecessary chrono access
2025-02-10 06:51:07 -05:00
yhirose
8aad481c69 Fix test.yaml problem 2025-02-08 23:37:41 -05:00
yhirose
5814e121df Release v0.18.7 2025-02-08 15:53:35 -05:00
Florian Albrechtskirchinger
7adbccbaf7
Refine when content is expected (#2044)
Consider Content-Length and Transfer-Encoding headers when determining
whether to expect content. Don't handle the HTTP/2 connection preface
pseudo-method PRI.

Fixes #2028.
2025-02-08 15:51:52 -05:00
yhirose
eb10c22db1 Add unit test for #609 2025-02-08 10:17:09 -05:00
yhirose
708f860e3a Fix #2042 2025-02-06 05:56:31 -05:00
yhirose
eb30f15363 Release v0.18.6 2025-02-05 19:14:20 -05:00
yhirose
4941d5b56b
Fix #2033 (#2039) 2025-02-05 12:46:33 -05:00
Florian Albrechtskirchinger
9bbb4741b4
Run clang-format (#2037) 2025-02-02 22:32:33 -05:00
yhirose
282f2feb77 Add a unit test 2025-02-01 22:11:15 -05:00
alex-cornford
60a1f00618
Support building httplib.h on OpenVMS x86 systems (#2031)
Modify for OpenVMS x86 C++. Make tests on OpenVMS currently not supported due to no cmake support.
Changes tested on OpenVMS clang C++ and Fedora & GCC
2025-01-28 18:44:22 -05:00
yhirose
9104054ca5 Fix README example 2025-01-27 13:37:16 -05:00
Baiyies
d69f144a99
Update httplib.h (#2030)
fix 'max'
2025-01-26 08:50:10 -05:00
yhirose
929dfbd348 Update copyright year 2025-01-20 00:32:10 -05:00
yhirose
3047183fd9 Update README 2025-01-20 00:02:02 -05:00
yhirose
ef5e4044f1 Update README 2025-01-19 23:46:12 -05:00
yhirose
3779800322 Release v0.18.5 2025-01-17 17:38:03 -05:00
yhirose
986a20fb7d
Resolve #2017 (#2022)
* Resolve #2017

* Fix warning

* Update README
2025-01-17 17:37:07 -05:00
yhirose
8311e1105f Fix Windows build problem 2025-01-16 23:26:04 -05:00
yhirose
ba6845925d Fix #2014 2025-01-16 23:10:58 -05:00
yhirose
343a0fc073 Fix #2011 2025-01-16 21:38:45 -05:00
yhirose
54f8a4d0f3 Release v0.18.4 2025-01-16 01:00:25 -05:00
yhirose
9c36aae4b7 Fix HTTP Response Splitting Vulnerability 2025-01-16 00:04:33 -05:00
yhirose
b766025a83 clangformat 2025-01-16 00:03:10 -05:00
yhirose
9b5f76f833 Fix #2012 2024-12-27 17:19:23 -05:00
sinnren
d647f484a4
fix:set_file_content with range request return 416. (#2010)
Co-authored-by: fenlog <bakurise@qq.com>
2024-12-24 09:38:59 -05:00
Sergey Bobrenok
8794792baa
Treat out-of-range last_pos as the end of the content (#2009)
RFC-9110 '14.1.2. Byte Ranges':
A client can limit the number of bytes requested without knowing the
size of the selected representation. If the last-pos value is absent,
or if the value is greater than or equal to the current length of the
representation data, the byte range is interpreted as the remainder of
the representation (i.e., the server replaces the value of last-pos
with a value that is one less than the current length of the selected
representation).

https://www.rfc-editor.org/rfc/rfc9110.html#section-14.1.2-6
2024-12-23 13:14:36 -05:00
yhirose
b85768c1f3 Fix #2005 2024-12-16 17:43:50 -05:00
yhirose
e6d71bd702 Add a unit test for Issue #2004 2024-12-12 18:15:22 -05:00
yhirose
258992a160 Changed to use non-blocking socket in is_ssl_peer_could_be_closed 2024-12-03 19:26:08 -05:00
yhirose
a7bc00e330 Release v0.18.3 2024-12-03 06:33:00 -05:00
yhirose
11a40584e9 Fix #1998 2024-12-03 00:38:20 -05:00
yhirose
3e86bdb4d8
Fix #1997 (#2001) 2024-12-03 00:11:29 -05:00
Pavel P
c817d65695
Fix casting uint64_t to size_t for 32-bit builds (#1999) 2024-12-02 11:09:52 -05:00
yhirose
51dee793fe Release v0.18.2 2024-11-29 20:49:50 -05:00
yhirose
457fc4306e Fix #1993 2024-11-29 20:46:48 -05:00
yhirose
4f5b003e76 Fix #1992 2024-11-28 20:40:38 -05:00
yhirose
5421e27106 Fix a compiler warning 2024-11-28 20:39:26 -05:00
yhirose
fe07660f40
Fix #1986 (#1988) 2024-11-27 12:18:35 -05:00
yhirose
da2f9e476e
Fix #1985 (#1989) 2024-11-27 12:18:23 -05:00
sebastianas
1a7a7ed1c3
test: Don't check for the exact size of compressed content. (#1984)
The testsuite checks for the exact size of the compressed content. The
exact size can change if the zlib library is using a different strategy.
In thise case using zlib-ng results in a slightly larger content leading
to a failure in the test.

Check that the compressed content is less than 10MiB which is a tenth of
the orignal content and proves that compression works.

Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
2024-11-25 15:46:41 -05:00
yhirose
413994912d Update vcxproj files 2024-11-16 11:14:13 -05:00
yhirose
01dcf1d0ad
Fix #1969 (without unnecessary sleep_for) (#1982) 2024-11-16 10:56:57 -05:00
yhirose
8e378779c2 Update README 2024-11-16 09:45:04 -05:00
yhirose
970b52897c
Fix #1980
Fix #1980
2024-11-16 02:09:52 -05:00
yhirose
412ba04d19 Fix problem caused by #1975 2024-11-14 20:33:08 -05:00
yhirose
bfef4b3e9b Fix #1975 2024-11-14 17:27:28 -05:00
yhirose
7bd316f3d0 Fix #1977 2024-11-14 16:46:27 -05:00
yhirose
26208363ee Fix warning 2024-11-14 16:46:09 -05:00
yhirose
b1b4bb8850 clangformat 2024-11-13 22:50:03 -05:00
yhirose
9dd565b6e3
Resolve #1973 (#1976)
* Fix #1973

* Fixed problems with 'Language for non-Unicode programs' setting on Windows

* Fix problems on English locale
2024-11-13 22:47:09 -05:00
yhirose
924f214303 Added unit test for exception handler 2024-11-02 07:23:44 -04:00
yhirose
5c1a34e766 Release v0.18.1 2024-10-18 17:16:54 -04:00
yhirose
fa90d06dd5 Merge branch 'master' of github.com:yhirose/cpp-httplib 2024-10-18 17:16:14 -04:00
Jiwoo Park
d869054318
Allow empty header values (#1965) 2024-10-18 10:16:48 -04:00
Peter Boström
0cc1ca9a8d
Remove extra semicolon (#1963)
This fixes a -Wc++98-compat-extra-semi instance.
2024-10-15 00:09:04 -04:00
yhirose
3701195033 Merge branch 'master' of github.com:yhirose/cpp-httplib 2024-10-14 21:32:28 -04:00
Peter Boström
f884a56258
Remove space between operator"" and _t (#1962)
This should fix a -Wdeprecated-literal-operator instance since this is
deprecated as a result of CWG2521 (iiuc C++23).
2024-10-14 21:32:13 -04:00
yhirose
d79633ff52 clangformat 2024-10-11 14:49:46 -04:00
yhirose
e0ebc431dc Fix #1959 2024-10-11 13:43:01 -04:00
Andrew McDaniel
131bc6c674
Add documentation for using Unix domain sockets. (#1954)
* Add documentation for using unix domain sockets.

* Formatting
2024-10-03 10:53:25 -04:00
yhirose
10d68cff50 Added a unit test for #1946 2024-09-26 22:24:44 -04:00
zjyhjqs
996acc5253
Feat: add CPack support (#1950) 2024-09-25 00:19:41 -04:00
yhirose
7c4799d0cf
Fix #1798 for CMake (#1944) 2024-09-19 18:33:32 -04:00
yhirose
c239087332 Fix Mafile errors 2024-09-17 18:37:44 -04:00
Andrea Pappacoda
7018e9263d
test(meson): copy files in www directory (#1941)
These files were added in commits
2d01e71286 and
b8315278cb
2024-09-17 18:06:01 -04:00
yhirose
4990b4b4b7 Fix problems with SSLSlientServerTest.* tests 2024-09-17 17:00:17 -04:00
Andrea Pappacoda
5064373c23
test(meson): fix SSLClientServerTest.* tests with OpenSSL 3.2.0 (#1940)
* build(meson): bump minimum version to 0.62.0

This allows making some minor cleanups

* test(meson): fix SSLClientServerTest.* tests with OpenSSL 3.2.0

Since OpenSSL commit
<342e3652c7>,
the default X.509 certificate format generated with the `openssl req`
command has been changed to X.509 v3 from X.509 v1.

For some reason, this change breaks cpp-httplib's SSLClientServerTest.*
tests.

To fix the test failures, this patch passes the '-x509v1' flag instead
of '-x509' when OpenSSL 3.2.0 or newer is detected. To detect the
version of a command line utility, Meson 0.62.0 or later is required.

Fixes <https://github.com/yhirose/cpp-httplib/issues/1798>, but only for
the Meson build system.
2024-09-17 16:58:09 -04:00
yhirose
6c93aea59a Revert "Enabled HostnameToIPConversionTest.YouTube_Online partially"
This reverts commit 6553cdedab.
2024-09-15 01:18:20 -04:00
yhirose
6553cdedab Enabled HostnameToIPConversionTest.YouTube_Online partially 2024-09-13 20:45:59 -04:00
yhirose
a61b2427b0 Update benchmark base vertion to 0.18.0 2024-09-13 20:34:30 -04:00
yhirose
af4ece3d5f Update benchmark/Makefile 2024-09-12 20:41:56 -04:00
yhirose
e64379c3d7 Release v0.18.0 2024-09-12 12:28:35 -04:00
yhirose
5053912534 Updated actions/upload-artifact from v1 to v4 2024-09-12 12:04:25 -04:00
Jean-Francois Simoneau
932b1cbc32
Fix shadow parameter warning (#1936) 2024-09-12 12:02:25 -04:00
yhirose
de36ea7755 Fix #1933 on Linux and macOS 2024-09-09 23:07:27 -04:00
yhirose
9f8db2c230 Fix #1933 2024-09-09 22:22:56 -04:00
yhirose
3f00e1b321 Revert "Changed set_file_content to accept only a regular file path."
This reverts commit 7ab9c119ef.
2024-09-09 20:03:47 -04:00
yhirose
7ab9c119ef Changed set_file_content to accept only a regular file path. 2024-09-09 19:59:18 -04:00
yhirose
3f2922b3fa Fix #1929 2024-09-09 19:25:52 -04:00
yhirose
509f583dca Fix problem caused by #1931. 2024-09-09 19:19:52 -04:00
Paul Harris
2d01e71286
Test reading empty zero-length file (#1931) 2024-09-09 17:54:11 -04:00
yhirose
e612154694
Issue1431 (#1926)
* Renamed enable_server_host_verification to enable_server_hostname_verification and added Error::SSLServerHostnameVerification

* Add some Open SSL function calls

* Code cleanup

* Fix #1431
2024-09-08 22:45:47 -04:00
yhirose
82fcbe3901 Code cleanup 2024-09-08 20:10:35 -04:00
yhirose
dbd2465b56 Add some Open SSL function calls 2024-09-08 20:10:17 -04:00
yhirose
ea79494b29 Renamed enable_server_host_verification to enable_server_hostname_verification and added Error::SSLServerHostnameVerification 2024-09-08 20:08:52 -04:00
yhirose
f35aff84c2 Fixed FuzzableServer build error 2024-09-08 19:00:23 -04:00
yhirose
7b18ae6f16 Update benchmark 2024-09-08 10:56:13 -04:00
yhirose
a79c56d06b Fix #1796 2024-09-08 09:26:19 -04:00
yhirose
3d6e315a4c Fix #1923 2024-09-08 08:38:36 -04:00
yhirose
4c27f9c6ef Made default server and client read/write timeout settings separately 2024-09-07 21:06:23 -04:00
yhirose
d173a37d17 Increased CPPHTTPLIB_READ_TIMEOUT_SECOND to 300 from 5 2024-09-07 16:10:54 -04:00
yhirose
7fd346a2ca Fix #1379 2024-09-07 16:07:45 -04:00
yhirose
c673d502b9 Update server_and_client.cc 2024-09-07 11:11:57 -04:00
yhirose
c43c51362a Add monitor tool 2024-09-07 10:16:15 -04:00
yhirose
3e86d93d13 clangformat 2024-09-07 10:16:03 -04:00
yhirose
f6e4e2d0f3 Code cleanup 2024-09-07 10:15:22 -04:00
yhirose
01a52aa8bd Add example/server_and_client.cc 2024-09-07 10:05:53 -04:00
yhirose
8415bf0823 Resolve #1906 2024-09-07 00:05:41 -04:00
orbea
327ff263f5
httplib.h: support LibreSSL (#1922) 2024-09-06 22:19:53 -04:00
yhirose
61c418048d Release v0.17.3 2024-09-06 19:58:02 -04:00
yhirose
9720ef8c34 Code cleanup 2024-09-06 19:48:25 -04:00
yhirose
978a4f6345
Fix KeepAliveTest.SSLClientReconnectionPost problem (#1921) 2024-09-06 13:58:24 -04:00
bgs99
80fb03628b
Only match path params that span full path segment (#1919)
* Only match path params that span full path segment

* Fix C++11 build
2024-09-06 08:48:51 -04:00
laowai9189
2480c0342c
‘constexpr’ error (#1918)
httplib.h: In member function ‘constexpr size_t httplib::detail::case_ignore_hash::operator()(const string&) const’:
httplib.h:359:30: error: call to non-‘constexpr’ function ‘const _CharT* std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::data() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
  359 |     return hash_core(key.data(), key.size(), 0);
2024-09-06 07:23:29 -04:00
bgs99
eb6f610a45
Fix find_package for curl (#1920) 2024-09-06 07:22:03 -04:00
yhirose
cb74e4191b Performance imporovement for Keep-Alive 2024-09-06 00:03:43 -04:00
yhirose
dfa641ca41 Misc 2024-09-05 22:54:48 -04:00
yhirose
969a9f99d5 Adjust sleep 2024-09-05 22:54:28 -04:00
yhirose
c099b42ba3 Removed write_format 2024-09-05 22:17:56 -04:00
yhirose
b8315278cb Add a missing file 2024-09-05 19:35:43 -04:00
yhirose
485f8f2411 Added one more case to MountTest.Redicect unit test. 2024-09-05 17:49:12 -04:00
yhirose
953e4f3841 Adjust sleep duration 2024-09-05 17:45:09 -04:00
yhirose
adf65cfe61 Target C++11 for benchmark 2024-09-05 17:44:51 -04:00
yhirose
12c829f6d3 Fix #1389 and #1907 2024-09-05 17:44:32 -04:00
yhirose
913314f1b1 Fix warning 2024-09-05 17:43:51 -04:00
yhirose
ef63f97afe Release v0.17.2 2024-09-05 12:57:26 -04:00
yhirose
bda74db01d Fix fuzzing test error 2024-09-05 12:50:05 -04:00
yhirose
9ff3ff9446 Fixed build error 2024-09-05 12:27:50 -04:00
yhirose
c75d071615 Add benchmark tool 2024-09-05 12:22:46 -04:00
yhirose
b4989130da Peformance improvement by removing tolower function call 2024-09-05 12:09:38 -04:00
yhirose
4fc0303bda clangformat 2024-09-05 12:07:35 -04:00
yhirose
3d9cc51851 Fixed build error on Windows due to max macro in windows.h 2024-09-05 12:02:40 -04:00
Andrea Pappacoda
f69587656f
build(meson): add libcurl test dependency (#1914)
Prompted by PR #1911
2024-09-04 18:05:03 -04:00
yhirose
d5fc340c30 Update README 2024-09-04 12:23:48 -04:00
yhirose
d79a547dc9 Merge branch 'solarispika-fix-100-continue' 2024-09-04 10:17:01 -04:00
yhirose
bd1da4346a Disable Expect100ContinueTest test on Windows 2024-09-04 09:51:36 -04:00
yhirose
4c2a608a0c Fix GitHub Actions errors 2024-09-04 09:06:27 -04:00
yhirose
ee4eb8deaa Merge branch 'fix-100-continue' of github.com:solarispika/cpp-httplib into solarispika-fix-100-continue 2024-09-04 08:45:48 -04:00
Sung, Po Han
7196ac8a07 Fix incorrect handling of Expect: 100-continue
Fix #1808
2024-09-04 17:50:42 +08:00
36 changed files with 27048 additions and 818 deletions

69
.github/workflows/abidiff.yaml vendored Normal file
View File

@ -0,0 +1,69 @@
# SPDX-FileCopyrightText: 2025 Andrea Pappacoda <andrea@pappacoda.it>
# SPDX-License-Identifier: MIT
name: abidiff
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
defaults:
run:
shell: sh
jobs:
abi:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
container:
image: debian:testing
steps:
- name: Install dependencies
run: apt -y --update install --no-install-recommends
abigail-tools
ca-certificates
g++
git
libbrotli-dev
libssl-dev
meson
pkg-config
python3
zlib1g-dev
- uses: actions/checkout@v4
with:
path: current
- uses: actions/checkout@v4
with:
path: previous
fetch-depth: 0
- name: Checkout previous
working-directory: previous
run: |
git switch master
git describe --tags --abbrev=0 master | xargs git checkout
- name: Build current
working-directory: current
run: |
meson setup --buildtype=debug -Dcpp-httplib_compile=true build
ninja -C build
- name: Build previous
working-directory: previous
run: |
meson setup --buildtype=debug -Dcpp-httplib_compile=true build
ninja -C build
- name: Run abidiff
run: abidiff
--headers-dir1 previous/build
--headers-dir2 current/build
previous/build/libcpp-httplib.so
current/build/libcpp-httplib.so

View File

@ -1,5 +1,11 @@
name: CIFuzz
on: [pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
jobs:
Fuzzing:
runs-on: ubuntu-latest
@ -19,7 +25,7 @@ jobs:
dry-run: false
language: c++
- name: Upload Crash
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View File

@ -1,43 +1,126 @@
name: test
on: [push, pull_request]
on:
push:
pull_request:
workflow_dispatch:
inputs:
gtest_filter:
description: 'Google Test filter'
test_linux:
description: 'Test on Linux'
type: boolean
default: true
test_macos:
description: 'Test on MacOS'
type: boolean
default: true
test_windows:
description: 'Test on Windows'
type: boolean
default: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
env:
GTEST_FILTER: ${{ github.event.inputs.gtest_filter || '*' }}
jobs:
ubuntu:
style-check:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
continue-on-error: true
steps:
- name: checkout
uses: actions/checkout@v4
- name: install brotli
run: sudo apt-get update && sudo apt-get install -y libbrotli-dev
- name: run style check
run: |
clang-format --version
cd test && make style_check
ubuntu:
runs-on: ubuntu-latest
if: >
(github.event_name == 'push') ||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_linux == 'true')
steps:
- name: checkout
uses: actions/checkout@v4
- name: install libraries
run: sudo apt-get update && sudo apt-get install -y libbrotli-dev libcurl4-openssl-dev
- name: build and run tests
run: cd test && make -j4
run: cd test && make
- name: run fuzz test target
run: cd test && make fuzz_test
macos:
runs-on: macos-latest
if: >
(github.event_name == 'push') ||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_macos == 'true')
steps:
- name: checkout
uses: actions/checkout@v4
- name: build and run tests
run: |
cd test && make -j2
run: cd test && make
- name: run fuzz test target
run: cd test && make fuzz_test
windows:
runs-on: windows-latest
if: >
(github.event_name == 'push') ||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.test_windows == 'true')
strategy:
matrix:
config:
- with_ssl: false
name: without SSL
- with_ssl: true
name: with SSL
name: windows ${{ matrix.config.name }}
steps:
- name: prepare git for checkout on windows
- name: Prepare Git for Checkout on Windows
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: checkout
- name: Checkout
uses: actions/checkout@v4
- name: setup msbuild on windows
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@v7
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Setup msbuild on windows
uses: microsoft/setup-msbuild@v2
- name: make-windows
run: |
cd test
msbuild.exe test.sln /verbosity:minimal /t:Build "/p:Configuration=Release;Platform=x64"
x64\Release\test.exe
- name: Install vcpkg dependencies
run: vcpkg install gtest curl zlib brotli
- name: Install OpenSSL
if: ${{ matrix.config.with_ssl }}
run: choco install openssl
- name: Configure CMake ${{ matrix.config.name }}
run: >
cmake -B build -S .
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_TOOLCHAIN_FILE=${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake
-DHTTPLIB_TEST=ON
-DHTTPLIB_REQUIRE_ZLIB=ON
-DHTTPLIB_REQUIRE_BROTLI=ON
-DHTTPLIB_REQUIRE_OPENSSL=${{ matrix.config.with_ssl && 'ON' || 'OFF' }}
- name: Build ${{ matrix.config.name }}
run: cmake --build build --config Release -- /v:m /clp:ShowCommandLine
- name: Run tests ${{ matrix.config.name }}
run: ctest --output-on-failure --test-dir build -C Release
env:
VCPKG_ROOT: "C:/vcpkg"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"

6
.gitignore vendored
View File

@ -9,6 +9,8 @@ example/benchmark
example/redirect
example/sse*
example/upload
example/one_time_request
example/server_and_client
example/*.pem
test/httplib.cc
test/httplib.h
@ -21,6 +23,9 @@ test/test.xcodeproj/*/xcuser*
test/*.o
test/*.pem
test/*.srl
test/_build_*
work/
benchmark/server*
*.swp
@ -34,6 +39,7 @@ Release
*.db
ipch
*.dSYM
*.pyc
.*
!/.gitattributes
!/.travis.yml

View File

@ -299,6 +299,8 @@ if(HTTPLIB_INSTALL)
# ex: /usr/share/doc/httplib/README.md and /usr/share/licenses/httplib/LICENSE
install(FILES "README.md" DESTINATION "${CMAKE_INSTALL_DOCDIR}")
install(FILES "LICENSE" DESTINATION "${CMAKE_INSTALL_DATADIR}/licenses/${PROJECT_NAME}")
include(CPack)
endif()
if(HTTPLIB_TEST)

View File

@ -2,7 +2,7 @@ FROM yhirose4dockerhub/ubuntu-builder AS builder
WORKDIR /build
COPY httplib.h .
COPY docker/main.cc .
RUN g++ -std=c++23 -static -o server -O2 -I. -DCPPHTTPLIB_USE_POLL main.cc && strip server
RUN g++ -std=c++23 -static -o server -O2 -I. main.cc && strip server
FROM scratch
COPY --from=builder /build/server /server

View File

@ -39,10 +39,10 @@ svr.listen("0.0.0.0", 8080);
#include "path/to/httplib.h"
// HTTP
httplib::Client cli("http://cpp-httplib-server.yhirose.repl.co");
httplib::Client cli("http://yhirose.github.io");
// HTTPS
httplib::Client cli("https://cpp-httplib-server.yhirose.repl.co");
httplib::Client cli("https://yhirose.github.io");
auto res = cli.Get("/hi");
res->status;
@ -77,6 +77,9 @@ cli.set_ca_cert_path("./ca-bundle.crt");
// Disable cert verification
cli.enable_server_certificate_verification(false);
// Disable host verification
cli.enable_server_hostname_verification(false);
```
> [!NOTE]
@ -122,6 +125,21 @@ int main(void)
res.set_content(req.body, "text/plain");
});
// If the handler takes time to finish, you can also poll the connection state
svr.Get("/task", [&](const Request& req, Response& res) {
const char * result = nullptr;
process.run(); // for example, starting an external process
while (result == nullptr) {
sleep(1);
if (req.is_connection_closed()) {
process.kill(); // kill the process
return;
}
result = process.stdout(); // != nullptr if the process finishes
}
res.set_content(result, "text/plain");
});
svr.Get("/stop", [&](const Request& req, Response& res) {
svr.stop();
});
@ -384,6 +402,18 @@ svr.Get("/chunked", [&](const Request& req, Response& res) {
});
```
### Send file content
```cpp
svr.Get("/content", [&](const Request &req, Response &res) {
res.set_file_content("./path/to/content.html");
});
svr.Get("/content", [&](const Request &req, Response &res) {
res.set_file_content("./path/to/content", "text/html");
});
```
### 'Expect: 100-continue' handler
By default, the server sends a `100 Continue` response for an `Expect: 100-continue` header.
@ -432,7 +462,7 @@ Please see [Server example](https://github.com/yhirose/cpp-httplib/blob/master/e
### Default thread pool support
`ThreadPool` is used as a **default** task queue, and the default thread count is 8, or `std::thread::hardware_concurrency()`. You can change it with `CPPHTTPLIB_THREAD_POOL_COUNT`.
`ThreadPool` is used as the **default** task queue, with a default thread count of 8 or `std::thread::hardware_concurrency() - 1`, whichever is greater. You can change it with `CPPHTTPLIB_THREAD_POOL_COUNT`.
If you want to set the thread count at runtime, there is no convenient way... But here is how.
@ -542,18 +572,18 @@ enum Error {
```c++
httplib::Headers headers = {
{ "Accept-Encoding", "gzip, deflate" }
{ "Hello", "World!" }
};
auto res = cli.Get("/hi", headers);
```
or
```c++
auto res = cli.Get("/hi", {{"Accept-Encoding", "gzip, deflate"}});
auto res = cli.Get("/hi", {{"Hello", "World!"}});
```
or
```c++
cli.set_default_headers({
{ "Accept-Encoding", "gzip, deflate" }
{ "Hello", "World!" }
});
auto res = cli.Get("/hi");
```
@ -624,6 +654,9 @@ res = cli.Options("/resource/foo");
cli.set_connection_timeout(0, 300000); // 300 milliseconds
cli.set_read_timeout(5, 0); // 5 seconds
cli.set_write_timeout(5, 0); // 5 seconds
// This method works the same as curl's `--max-timeout` option
svr.set_max_timeout(5000); // 5 seconds
```
### Receive content with a content receiver
@ -808,6 +841,21 @@ The server can apply compression to the following MIME type contents:
Brotli compression is available with `CPPHTTPLIB_BROTLI_SUPPORT`. Necessary libraries should be linked.
Please see https://github.com/google/brotli for more detail.
### Default `Accept-Encoding` value
The default `Accept-Encoding` value contains all possible compression types. So, the following two examples are same.
```c++
res = cli.Get("/resource/foo");
res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
```
If we don't want a response without compression, we have to set `Accept-Encoding` to an empty string. This behavior is similar to curl.
```c++
res = cli.Get("/resource/foo", {{"Accept-Encoding", ""}});
```
### Compress request body on client
```c++
@ -819,14 +867,27 @@ res = cli.Post("/resource/foo", "...", "text/plain");
```c++
cli.set_decompress(false);
res = cli.Get("/resource/foo", {{"Accept-Encoding", "gzip, deflate, br"}});
res = cli.Get("/resource/foo");
res->body; // Compressed data
```
Use `poll` instead of `select`
------------------------------
Unix Domain Socket Support
--------------------------
`select` system call is used as default since it's more widely supported. If you want to let cpp-httplib use `poll` instead, you can do so with `CPPHTTPLIB_USE_POLL`.
Unix Domain Socket support is available on Linux and macOS.
```c++
// Server
httplib::Server svr;
svr.set_address_family(AF_UNIX).listen("./my-socket.sock", 80);
// Client
httplib::Client cli("./my-socket.sock");
cli.set_address_family(AF_UNIX);
```
"my-socket.sock" can be a relative path or an absolute path. You application must have the appropriate permissions for the path. You can also use an abstract socket address on Linux. To use an abstract socket address, prepend a null byte ('\x00') to the path.
Split httplib.h into .h and .cc
@ -857,7 +918,17 @@ Dockerfile for static HTTP server is available. Port number of this HTTP server
> docker build -t cpp-httplib-server .
...
> docker run --init --rm -it -p 8080:80 -v ./docker/html:/html cpp-httplib-server
> docker run --rm -it -p 8080:80 -v ./docker/html:/html cpp-httplib-server
Serving HTTP on 0.0.0.0 port 80 ...
192.168.65.1 - - [31/Aug/2024:21:33:56 +0000] "GET / HTTP/1.1" 200 599 "-" "curl/8.7.1"
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET / HTTP/1.1" 200 599 "-" "Mozilla/5.0 ..."
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET /favicon.ico HTTP/1.1" 404 152 "-" "Mozilla/5.0 ..."
```
From Docker Hub
```bash
> docker run --rm -it -p 8080:80 -v ./docker/html:/html yhirose4dockerhub/cpp-httplib-server
Serving HTTP on 0.0.0.0 port 80 ...
192.168.65.1 - - [31/Aug/2024:21:33:56 +0000] "GET / HTTP/1.1" 200 599 "-" "curl/8.7.1"
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET / HTTP/1.1" 200 599 "-" "Mozilla/5.0 ..."
@ -890,12 +961,12 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
> cpp-httplib officially supports only the latest Visual Studio. It might work with former versions of Visual Studio, but I can no longer verify it. Pull requests are always welcome for the older versions of Visual Studio unless they break the C++11 conformance.
> [!NOTE]
> Windows 8 or lower, Visual Studio 2013 or lower, and Cygwin and MSYS2 including MinGW are neither supported nor tested.
> Windows 8 or lower, Visual Studio 2015 or lower, and Cygwin and MSYS2 including MinGW are neither supported nor tested.
License
-------
MIT license (© 2024 Yuji Hirose)
MIT license (© 2025 Yuji Hirose)
Special Thanks To
-----------------

62
benchmark/Makefile Normal file
View File

@ -0,0 +1,62 @@
CXXFLAGS = -std=c++11 -O2 -I..
CPPHTTPLIB_FLAGS = -DCPPHTTPLIB_THREAD_POOL_COUNT=16
BENCH = bombardier -c 10 -d 5s localhost:8080
MONITOR = ali http://localhost:8080
# cpp-httplib
bench: server
@echo "--------------------\n cpp-httplib latest\n--------------------\n"
@./server & export PID=$$!; $(BENCH); kill $${PID}
@echo ""
monitor: server
@./server & export PID=$$!; $(MONITOR); kill $${PID}
run : server
@./server
server : cpp-httplib/main.cpp ../httplib.h
g++ -o $@ $(CXXFLAGS) $(CPPHTTPLIB_FLAGS) cpp-httplib/main.cpp
# cpp-httplib
bench-base: server-base
@echo "---------------------\n cpp-httplib v0.18.0\n---------------------\n"
@./server-base & export PID=$$!; $(BENCH); kill $${PID}
@echo ""
monitor-base: server-base
@./server-base & export PID=$$!; $(MONITOR); kill $${PID}
run-base : server-base
@./server-base
server-base : cpp-httplib-base/main.cpp cpp-httplib-base/httplib.h
g++ -o $@ $(CXXFLAGS) $(CPPHTTPLIB_FLAGS) cpp-httplib-base/main.cpp
# crow
bench-crow: server-crow
@echo "-------------\n Crow v1.2.0\n-------------\n"
@./server-crow & export PID=$$!; $(BENCH); kill $${PID}
@echo ""
monitor-crow: server-crow
@./server-crow & export PID=$$!; $(MONITOR); kill $${PID}
run-crow : server-crow
@./server-crow
server-crow : crow/main.cpp
g++ -o $@ $(CXXFLAGS) crow/main.cpp
# misc
build: server server-base server-crow
bench-all: bench-crow bench bench-base
issue:
bombardier -c 10 -d 30s localhost:8080
clean:
rm -rf server*

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
#include "./httplib.h"
using namespace httplib;
int main() {
Server svr;
svr.Get("/", [](const Request &, Response &res) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("0.0.0.0", 8080);
}

View File

@ -0,0 +1,12 @@
#include "httplib.h"
using namespace httplib;
int main() {
Server svr;
svr.Get("/", [](const Request &, Response &res) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("0.0.0.0", 8080);
}

14316
benchmark/crow/crow_all.h Normal file

File diff suppressed because it is too large Load Diff

17
benchmark/crow/main.cpp Normal file
View File

@ -0,0 +1,17 @@
#include "crow_all.h"
class CustomLogger : public crow::ILogHandler {
public:
void log(std::string, crow::LogLevel) {}
};
int main() {
CustomLogger logger;
crow::logger::setHandler(&logger);
crow::SimpleApp app;
CROW_ROUTE(app, "/")([]() { return "Hello world!"; });
app.port(8080).multithreaded().run();
}

2
benchmark/download.sh Executable file
View File

@ -0,0 +1,2 @@
rm -f httplib.h
wget https://raw.githubusercontent.com/yhirose/cpp-httplib/v$1/httplib.h

View File

@ -1,7 +1,7 @@
//
// main.cc
//
// Copyright (c) 2024 Yuji Hirose. All rights reserved.
// Copyright (c) 2025 Yuji Hirose. All rights reserved.
// MIT License
//
@ -41,7 +41,7 @@ std::string log(auto &req, auto &res) {
auto http_referer = "-"; // TODO:
auto http_user_agent = req.get_header_value("User-Agent", "-");
// NOTE: From NGINX defualt access log format
// NOTE: From NGINX default access log format
// log_format combined '$remote_addr - $remote_user [$time_local] '
// '"$request" $status $body_bytes_sent '
// '"$http_referer" "$http_user_agent"';

View File

@ -18,7 +18,7 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
BROTLI_DIR = $(PREFIX)/opt/brotli
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark issue
all: server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark one_time_request server_and_client
server : server.cc ../httplib.h Makefile
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
@ -53,9 +53,12 @@ benchmark : benchmark.cc ../httplib.h Makefile
one_time_request : one_time_request.cc ../httplib.h Makefile
$(CXX) -o one_time_request $(CXXFLAGS) one_time_request.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
server_and_client : server_and_client.cc ../httplib.h Makefile
$(CXX) -o server_and_client $(CXXFLAGS) server_and_client.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
pem:
openssl genrsa 2048 > key.pem
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
clean:
rm server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark one_time_request *.pem
rm server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark one_time_request server_and_client *.pem

View File

@ -22,34 +22,34 @@
<ProjectGuid>{6DB1FC63-B153-4279-92B7-D8A11AF285D6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>client</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">

View File

@ -18,38 +18,41 @@
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="simplesvr.cc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{864CD288-050A-4C8B-9BEF-3048BD876C5B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>sample</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -151,9 +154,6 @@
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="server.cc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -0,0 +1,90 @@
//
// server_and_client.cc
//
// Copyright (c) 2025 Yuji Hirose. All rights reserved.
// MIT License
//
#include <httplib.h>
#include <iostream>
#include <string>
using namespace httplib;
std::string dump_headers(const Headers &headers) {
std::string s;
char buf[BUFSIZ];
for (auto it = headers.begin(); it != headers.end(); ++it) {
const auto &x = *it;
snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str());
s += buf;
}
return s;
}
void logger(const Request &req, const Response &res) {
std::string s;
char buf[BUFSIZ];
s += "================================\n";
snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
req.version.c_str(), req.path.c_str());
s += buf;
std::string query;
for (auto it = req.params.begin(); it != req.params.end(); ++it) {
const auto &x = *it;
snprintf(buf, sizeof(buf), "%c%s=%s",
(it == req.params.begin()) ? '?' : '&', x.first.c_str(),
x.second.c_str());
query += buf;
}
snprintf(buf, sizeof(buf), "%s\n", query.c_str());
s += buf;
s += dump_headers(req.headers);
s += "--------------------------------\n";
snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str());
s += buf;
s += dump_headers(res.headers);
s += "\n";
if (!res.body.empty()) { s += res.body; }
s += "\n";
std::cout << s;
}
int main(void) {
// Server
Server svr;
svr.set_logger(logger);
svr.Post("/post", [&](const Request & /*req*/, Response &res) {
res.set_content("POST", "text/plain");
});
auto th = std::thread([&]() { svr.listen("localhost", 8080); });
auto se = detail::scope_exit([&] {
svr.stop();
th.join();
});
svr.wait_until_ready();
// Client
Client cli{"localhost", 8080};
std::string body = R"({"hello": "world"})";
auto res = cli.Post("/post", body, "application/json");
std::cout << "--------------------------------" << std::endl;
std::cout << to_string(res.error()) << std::endl;
}

View File

@ -12,8 +12,7 @@ using namespace std;
class EventDispatcher {
public:
EventDispatcher() {
}
EventDispatcher() {}
void wait_event(DataSink *sink) {
unique_lock<mutex> lk(m_);

1672
httplib.h

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ project(
'b_lto=true',
'warning_level=3'
],
meson_version: '>=0.47.0'
meson_version: '>=0.62.0'
)
# Check just in case downstream decides to edit the source
@ -98,20 +98,18 @@ if get_option('cpp-httplib_compile')
)
else
install_headers('httplib.h')
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, include_directories: include_directories('.'))
cpp_httplib_dep = declare_dependency(compile_args: args, dependencies: deps, include_directories: '.')
import('pkgconfig').generate(
name: 'cpp-httplib',
description: 'A C++ HTTP/HTTPS server and client library',
install_dir: join_paths(get_option('datadir'), 'pkgconfig'),
install_dir: get_option('datadir')/'pkgconfig',
url: 'https://github.com/yhirose/cpp-httplib',
version: version
)
endif
if meson.version().version_compare('>=0.54.0')
meson.override_dependency('cpp-httplib', cpp_httplib_dep)
endif
meson.override_dependency('cpp-httplib', cpp_httplib_dep)
if get_option('cpp-httplib_test')
subdir('test')

View File

@ -24,9 +24,11 @@ else()
FetchContent_MakeAvailable(gtest)
endif()
add_executable(httplib-test test.cc)
find_package(CURL REQUIRED)
add_executable(httplib-test test.cc include_httplib.cc $<$<BOOL:${WIN32}>:include_windows_h.cc>)
target_compile_options(httplib-test PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/utf-8;/bigobj>")
target_link_libraries(httplib-test PRIVATE httplib GTest::gtest_main)
target_link_libraries(httplib-test PRIVATE httplib GTest::gtest_main CURL::libcurl)
gtest_discover_tests(httplib-test)
file(
@ -35,6 +37,11 @@ file(
)
if(HTTPLIB_IS_USING_OPENSSL)
if (OPENSSL_VERSION VERSION_LESS "3.2.0")
set(OPENSSL_X509_FLAG "-x509")
else()
set(OPENSSL_X509_FLAG "-x509v1")
endif()
find_program(OPENSSL_COMMAND
NAMES openssl
PATHS ${OPENSSL_INCLUDE_DIR}/../bin
@ -54,7 +61,7 @@ if(HTTPLIB_IS_USING_OPENSSL)
COMMAND_ERROR_IS_FATAL ANY
)
execute_process(
COMMAND ${OPENSSL_COMMAND} req -x509 -new -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
COMMAND ${OPENSSL_COMMAND} req ${OPENSSL_X509_FLAG} -new -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND_ERROR_IS_FATAL ANY
)
@ -65,7 +72,7 @@ if(HTTPLIB_IS_USING_OPENSSL)
COMMAND_ERROR_IS_FATAL ANY
)
execute_process(
COMMAND ${OPENSSL_COMMAND} req -x509 -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.rootCA.conf -key rootCA.key.pem -days 1024
COMMAND ${OPENSSL_COMMAND} req ${OPENSSL_X509_FLAG} -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.rootCA.conf -key rootCA.key.pem -days 1024
OUTPUT_FILE rootCA.cert.pem
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND_ERROR_IS_FATAL ANY

View File

@ -18,7 +18,7 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
BROTLI_DIR = $(PREFIX)/opt/brotli
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread
TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) -pthread -lcurl
# By default, use standalone_fuzz_target_runner.
# This runner does no fuzzing, but simply executes the inputs
@ -28,6 +28,11 @@ TEST_ARGS = gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUP
# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
CLANG_FORMAT = clang-format
REALPATH = $(shell which grealpath 2>/dev/null || which realpath 2>/dev/null)
STYLE_CHECK_FILES = $(filter-out httplib.h httplib.cc, \
$(wildcard example/*.h example/*.cc fuzzing/*.h fuzzing/*.cc *.h *.cc ../httplib.h))
all : test test_split
./test
@ -42,6 +47,31 @@ test : test.cc include_httplib.cc ../httplib.h Makefile cert.pem
test_split : test.cc ../httplib.h httplib.cc Makefile cert.pem
$(CXX) -o $@ $(CXXFLAGS) test.cc httplib.cc $(TEST_ARGS)
check_abi:
@./check-shared-library-abi-compatibility.sh
.PHONY: style_check
style_check: $(STYLE_CHECK_FILES)
@for file in $(STYLE_CHECK_FILES); do \
$(CLANG_FORMAT) $$file > $$file.formatted; \
if ! diff -u $$file $$file.formatted; then \
file2=$$($(REALPATH) --relative-to=.. $$file); \
printf "\n%*s\n" 80 | tr ' ' '#'; \
printf "##%*s##\n" 76; \
printf "## %-70s ##\n" "$$file2 not properly formatted. Please run clang-format."; \
printf "##%*s##\n" 76; \
printf "%*s\n\n" 80 | tr ' ' '#'; \
failed=1; \
fi; \
rm -f $$file.formatted; \
done; \
if [ -n "$$failed" ]; then \
echo "Style check failed for one or more files. See above for details."; \
false; \
else \
echo "All files are properly formatted."; \
fi
test_proxy : test_proxy.cc ../httplib.h Makefile cert.pem
$(CXX) -o $@ -I.. $(CXXFLAGS) test_proxy.cc $(TEST_ARGS)
@ -63,18 +93,8 @@ httplib.cc : ../httplib.h
python3 ../split.py -o .
cert.pem:
openssl genrsa 2048 > key.pem
openssl req -new -batch -config test.conf -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
openssl req -x509 -config test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
openssl genrsa 2048 > rootCA.key.pem
openssl req -x509 -new -batch -config test.rootCA.conf -key rootCA.key.pem -days 1024 > rootCA.cert.pem
openssl genrsa 2048 > client.key.pem
openssl req -new -batch -config test.conf -key client.key.pem | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client.cert.pem
openssl genrsa -passout pass:test123! 2048 > key_encrypted.pem
openssl req -new -batch -config test.conf -key key_encrypted.pem | openssl x509 -days 3650 -req -signkey key_encrypted.pem > cert_encrypted.pem
openssl genrsa -aes256 -passout pass:test012! 2048 > client_encrypted.key.pem
openssl req -new -batch -config test.conf -key client_encrypted.key.pem -passin pass:test012! | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client_encrypted.cert.pem
#c_rehash .
./gen-certs.sh
clean:
rm -f test test_split test_proxy server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc
rm -rf test test_split test_proxy server_fuzzer *.pem *.0 *.o *.1 *.srl httplib.h httplib.cc _build* *.dSYM

View File

@ -25,7 +25,9 @@ public:
bool is_readable() const override { return true; }
bool is_writable() const override { return true; }
bool wait_readable() const override { return true; }
bool wait_writable() const override { return true; }
void get_remote_ip_and_port(std::string &ip, int &port) const override {
ip = "127.0.0.1";
@ -39,6 +41,8 @@ public:
socket_t socket() const override { return 0; }
time_t duration() const override { return 0; };
private:
const uint8_t *data_;
size_t size_;
@ -50,8 +54,12 @@ class FuzzableServer : public httplib::Server {
public:
void ProcessFuzzedRequest(FuzzedStream &stream) {
bool connection_close = false;
process_request(stream, /*last_connection=*/false, connection_close,
nullptr);
process_request(stream,
/*remote_addr=*/"",
/*remote_port =*/0,
/*local_addr=*/"",
/*local_port =*/0,
/*last_connection=*/false, connection_close, nullptr);
}
};

18
test/gen-certs.sh Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
if [[ $(openssl version) =~ 3\.[2-9]\.[0-9]+ ]]; then
OPENSSL_X509_FLAG='-x509v1'
else
OPENSSL_X509_FLAG='-x509'
fi
openssl genrsa 2048 > key.pem
openssl req -new -batch -config test.conf -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
openssl req -x509 -config test.conf -key key.pem -sha256 -days 3650 -nodes -out cert2.pem -extensions SAN
openssl genrsa 2048 > rootCA.key.pem
openssl req $OPENSSL_X509_FLAG -new -batch -config test.rootCA.conf -key rootCA.key.pem -days 1024 > rootCA.cert.pem
openssl genrsa 2048 > client.key.pem
openssl req -new -batch -config test.conf -key client.key.pem | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client.cert.pem
openssl genrsa -passout pass:test123! 2048 > key_encrypted.pem
openssl req -new -batch -config test.conf -key key_encrypted.pem | openssl x509 -days 3650 -req -signkey key_encrypted.pem > cert_encrypted.pem
openssl genrsa -aes256 -passout pass:test012! 2048 > client_encrypted.key.pem
openssl req -new -batch -config test.conf -key client_encrypted.key.pem -passin pass:test012! | openssl x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial > client_encrypted.cert.pem

View File

@ -0,0 +1,6 @@
// Test if including windows.h conflicts with httplib.h
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <httplib.h>

28
test/make-shared-library.sh Executable file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env bash
if [ "$#" -ne 1 ]; then
echo "Usage: $0 build_dir"
exit 1
fi
BUILD_DIR=$1
# Make the build directory
rm -rf $BUILD_DIR
mkdir -p $BUILD_DIR/out
cd $BUILD_DIR
# Build the version
git checkout $BUILD_DIR -q
cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="-g -Og" \
-DBUILD_SHARED_LIBS=ON \
-DHTTPLIB_COMPILE=ON \
-DCMAKE_INSTALL_PREFIX=./out \
../..
cmake --build . --target install
cmake --build . --target clean

View File

@ -3,8 +3,10 @@
# SPDX-License-Identifier: MIT
gtest_dep = dependency('gtest', main: true)
libcurl_dep = dependency('libcurl')
openssl = find_program('openssl')
test_conf = files('test.conf')
req_x509_flag = openssl.version().version_compare('>=3.2.0') ? '-x509v1' : '-x509'
key_pem = custom_target(
'key_pem',
@ -30,7 +32,7 @@ cert2_pem = custom_target(
'cert2_pem',
input: key_pem,
output: 'cert2.pem',
command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
command: [openssl, 'req', req_x509_flag, '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
)
key_encrypted_pem = custom_target(
@ -43,7 +45,7 @@ cert_encrypted_pem = custom_target(
'cert_encrypted_pem',
input: key_encrypted_pem,
output: 'cert_encrypted.pem',
command: [openssl, 'req', '-x509', '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
command: [openssl, 'req', req_x509_flag, '-config', test_conf, '-key', '@INPUT@', '-sha256', '-days', '3650', '-nodes', '-out', '@OUTPUT@', '-extensions', 'SAN']
)
rootca_key_pem = custom_target(
@ -56,7 +58,7 @@ rootca_cert_pem = custom_target(
'rootca_cert_pem',
input: rootca_key_pem,
output: 'rootCA.cert.pem',
command: [openssl, 'req', '-x509', '-new', '-batch', '-config', files('test.rootCA.conf'), '-key', '@INPUT@', '-days', '1024', '-out', '@OUTPUT@']
command: [openssl, 'req', req_x509_flag, '-new', '-batch', '-config', files('test.rootCA.conf'), '-key', '@INPUT@', '-days', '1024', '-out', '@OUTPUT@']
)
client_key_pem = custom_target(
@ -102,9 +104,9 @@ client_encrypted_cert_pem = custom_target(
# Copy test files to the build directory
configure_file(input: 'ca-bundle.crt', output: 'ca-bundle.crt', copy: true)
configure_file(input: 'image.jpg', output: 'image.jpg', copy: true)
subdir(join_paths('www', 'dir'))
subdir(join_paths('www2', 'dir'))
subdir(join_paths('www3', 'dir'))
subdir('www')
subdir('www2'/'dir')
subdir('www3'/'dir')
# GoogleTest 1.13.0 requires C++14
test_options = []
@ -119,7 +121,8 @@ test(
'test.cc',
dependencies: [
cpp_httplib_dep,
gtest_dep
gtest_dep,
libcurl_dep
],
override_options: test_options
),

File diff suppressed because it is too large Load Diff

View File

@ -28,26 +28,26 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
@ -177,4 +177,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -5,8 +5,7 @@
using namespace std;
using namespace httplib;
template <typename T>
void ProxyTest(T& cli, bool basic) {
template <typename T> void ProxyTest(T &cli, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
auto res = cli.Get("/httpbin/get");
ASSERT_TRUE(res != nullptr);
@ -38,7 +37,7 @@ TEST(ProxyTest, SSLDigest) {
// ----------------------------------------------------------------------------
template <typename T>
void RedirectProxyText(T& cli, const char *path, bool basic) {
void RedirectProxyText(T &cli, const char *path, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
if (basic) {
cli.set_proxy_basic_auth("hello", "world");
@ -100,8 +99,7 @@ TEST(RedirectTest, YouTubeSSLDigest) {
// ----------------------------------------------------------------------------
template <typename T>
void BaseAuthTestFromHTTPWatch(T& cli) {
template <typename T> void BaseAuthTestFromHTTPWatch(T &cli) {
cli.set_proxy("localhost", 3128);
cli.set_proxy_basic_auth("hello", "world");
@ -112,11 +110,11 @@ void BaseAuthTestFromHTTPWatch(T& cli) {
}
{
auto res =
cli.Get("/basic-auth/hello/world",
{make_basic_authentication_header("hello", "world")});
auto res = cli.Get("/basic-auth/hello/world",
{make_basic_authentication_header("hello", "world")});
ASSERT_TRUE(res != nullptr);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
@ -124,7 +122,8 @@ void BaseAuthTestFromHTTPWatch(T& cli) {
cli.set_basic_auth("hello", "world");
auto res = cli.Get("/basic-auth/hello/world");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
@ -158,8 +157,7 @@ TEST(BaseAuthTest, SSL) {
// ----------------------------------------------------------------------------
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
template <typename T>
void DigestAuthTestFromHTTPWatch(T& cli) {
template <typename T> void DigestAuthTestFromHTTPWatch(T &cli) {
cli.set_proxy("localhost", 3129);
cli.set_proxy_digest_auth("hello", "world");
@ -181,7 +179,8 @@ void DigestAuthTestFromHTTPWatch(T& cli) {
for (auto path : paths) {
auto res = cli.Get(path.c_str());
ASSERT_TRUE(res != nullptr);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
@ -216,8 +215,7 @@ TEST(DigestAuthTest, NoSSL) {
// ----------------------------------------------------------------------------
template <typename T>
void KeepAliveTest(T& cli, bool basic) {
template <typename T> void KeepAliveTest(T &cli, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
if (basic) {
cli.set_proxy_basic_auth("hello", "world");
@ -249,9 +247,10 @@ void KeepAliveTest(T& cli, bool basic) {
"/httpbin/digest-auth/auth-int/hello/world/MD5",
};
for (auto path: paths) {
for (auto path : paths) {
auto res = cli.Get(path.c_str());
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res->body);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
}

0
test/www/empty_file Normal file
View File

1
test/www/file Normal file
View File

@ -0,0 +1 @@
file

7
test/www/meson.build Normal file
View File

@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2024 Andrea Pappacoda
#
# SPDX-License-Identifier: MIT
configure_file(input: 'empty_file', output: 'empty_file', copy: true)
configure_file(input: 'file', output: 'file', copy: true)
subdir('dir')

View File

@ -0,0 +1 @@
日本語コンテンツ