Compare commits

...

331 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
yhirose
c88b09bc6b Release v0.17.1 2024-09-03 21:20:57 -04:00
yhirose
87fab847b8 Fix SIGINT problem in Docker image 2024-09-03 21:20:10 -04:00
yhirose
4e6055f084 Fix problem with Abstract Namespace Unix Domain 2024-09-03 20:56:16 -04:00
yhirose
975cf0dae5 Fix #1908 2024-09-03 18:00:12 -04:00
yhirose
4854a694cd Use IPPROTO_IP 2024-09-03 17:29:28 -04:00
yhirose
b1f8e986bf
Fix #1908 (#1910)
* Fix #1908

* Code format
2024-09-03 00:47:39 -04:00
yhirose
c5ee208775 Fix build error on Mac and Linux 2024-09-02 23:04:38 -04:00
yhirose
ddfdacfa49 Fix build error 2024-09-02 22:49:31 -04:00
yhirose
2514ebc20f Fix #1848 2024-09-02 20:38:01 -04:00
yhirose
4f9c6540b2 Fixed warning 2024-09-02 20:33:33 -04:00
mol123
21c9a6a1ff
Windows: simplify conditional compilation and fix call to CreateFileMappingW. (#1909) 2024-09-02 18:01:05 -04:00
yhirose
7f6d413ddd Release v0.17.0 2024-09-01 07:53:56 -04:00
yhirose
88277139e7
Added set_ipv6_v6only method (#1905)
* Added `set_ipv6_v6only` method

* Adjust the place where socket_options is called
2024-09-01 07:52:24 -04:00
yhirose
6cdd3493a1 Fix #1788 2024-09-01 01:55:27 -04:00
yhirose
9c91b6f4a6 Fix #1645 2024-09-01 00:11:07 -04:00
yhirose
cee838e335 Documentation 2024-08-31 17:42:43 -04:00
yhirose
d82c82db2c Add sleep in handle_EINTR 2024-08-31 17:19:52 -04:00
yhirose
ba638ff38e Update Docker support 2024-08-31 17:09:20 -04:00
yhirose
da0c6579fa Breaking Change! get_header_ methods on Request and Response now take a default value. 2024-08-31 17:07:48 -04:00
yhirose
52a18c78a5 Add docker related files 2024-08-27 00:23:31 -04:00
yhirose
048edec9ed Changed CPPHTTPLIB_KEEPALIVE_MAX_COUNT to 100 2024-08-26 21:10:38 -04:00
yhirose
af56b7ec0b Release v0.16.3 2024-08-17 09:53:26 -04:00
Jiwoo Park
6c3e8482f7
Fix KeepAliveTest.SSLClientReconnectionPost (#1895) 2024-08-10 07:19:59 -04:00
yhirose
390f2c41f6
Fix #1878 (#1893)
* Fix #1878
2024-08-08 22:07:46 -04:00
yhirose
aa04feebb4 Fix warnings 2024-08-08 20:54:33 -04:00
yhirose
45f3694f82 Fix problem with clean command in Makefile 2024-08-08 19:30:46 -04:00
yhirose
c5c54b31e2 Release v0.16.2 2024-08-08 11:48:50 -04:00
Mark Mentovai
69c84c9597
BoringSSL compatibility fixes (#1892)
This patch is necessary to build cpp-httplib in Crashpad, itself in
Chromium, using BoringSSL. Details at [1].

The fixes include:
 - Library version check: tolerate BoringSSL as an alternative to
   OpenSSL 3.
 - Don’t call `OPENSSL_thread_stop`, which is not in BoringSSL.
 - Use `SSL_get_peer_certificate` (deprecated in OpenSSL 3), the old
   name for `SSL_get1_peer_certificate`, because the new name is not in
   BoringSSL.
 - Call `SSL_set_tlsext_host_name` directly instead of making an
   `SSL_ctrl` call that BoringSSL does not support. The feared
   -Wold-style-cast warning that occurs when buidling with OpenSSL is
   not triggered in BoringSSL.

[1] 1a62a01825
2024-08-08 11:47:56 -04:00
yhirose
ae63b89cbf Use SOCK_CLOEXEC instead of __linux__ 2024-08-06 17:31:55 -04:00
yhirose
ff038f98b7 Merge branch 'thread-safe-cloexec' of github.com:kdombroski/cpp-httplib into kdombroski-thread-safe-cloexec 2024-08-06 17:22:43 -04:00
yhirose
e00fd06355 Release v0.16.1 2024-08-06 17:04:22 -04:00
yhirose
521529d24d
Fix #1481 (with content provider) (#1527)
* Fix #1481 (with content provider)

* Improve shutdown performance

* Make shutdown action more stable

* Move some tests up

* Simplified

* Simplified
2024-08-06 13:43:00 -04:00
yhirose
ed0719f2bc Code format 2024-08-06 07:20:05 -04:00
hanslivingstone
6a848b1a16
Require a minimum of TLS 1.2 (#1889)
TLS 1. is deprecated: https://www.ietf.org/rfc/rfc8996.html
2024-07-30 17:18:33 -04:00
mol123
c8bcaf8a91
Fix build when targeting Windows 7 as platform. (#1869)
* Fix build when targeting Windows 7 as platform.

This change makes more of the code introduced in
https://github.com/yhirose/cpp-httplib/pull/1775
conditional on feature macros.

`CreateFile2`, `CreateFileMappingFromApp` and `MapViewOfFileFromApp` are
available only starting from Windows 8.

 * https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfile2
 * https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-createfilemappingfromapp
 * https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffilefromapp

* Update feature macros used and use `GetFileSizeEx` conditionally.
2024-07-02 10:58:40 -04:00
Hlado
8cd0ed0509
Added move assignment operator to Client class. (#1873) 2024-06-30 11:17:00 -04:00
Hlado
177d8420a1
Added .gitattributes file to prevent git from changing line endings (#1872)
of text files using as data for tests.
2024-06-30 11:16:48 -04:00
Daniel Ludwig
388a8c007c
Fix build on Windows with no WINAPI_PARTITION_APP support (#1865) 2024-06-24 15:13:37 -04:00
Andrea Pappacoda
bdefdce1ae
test: fix GetRangeWithMaxLongLength on 32 bit machines (#1867)
The test used the hardcoded long value for 64 bit machines even on 32
bit ones, leading to test failures. With this patch the max long length
is obtained using std::numeric_limits<long>::max(). Thanks to q2a3z for
the hint!

Fixes: https://github.com/yhirose/cpp-httplib/issues/1795
2024-06-23 17:49:00 -04:00
Zhenlin Huang
9e4f93d87e
Allow hex for ipv6 literal addr in redirect (#1859)
Co-authored-by: jaredhuang <jaredhuang@tencent.com>
2024-06-17 11:44:51 -04:00
yhirose
0b657d28cf Added example/one_time_request.cc. 2024-06-14 18:29:34 -04:00
Rainer Schielke
c1a09daf15
avoid memory leaks if linked with static openssl libs (#1857)
* New function SSLServer::update_certs. Allows to update certificates while server is running

* New function SSLServer::update_certs. Added unit test

* avoid memory leaks if linked with static openssl libs

---------

Co-authored-by: CEU\schielke <Rainer.Schielke@heidelberg.com>
2024-06-14 15:40:03 -04:00
yhirose
8438df4a95 Release v0.16.0 2024-06-11 18:20:47 -04:00
Jiwoo Park
67fd7e3d09
Change library name to cpp-httplib (#1854) 2024-06-10 13:18:19 -04:00
Rainer Schielke
d44031615d
New function SSLServer::update_certs. Allows to update certificates while server is running (#1827)
* New function SSLServer::update_certs. Allows to update certificates while server is running

* New function SSLServer::update_certs. Added unit test

---------

Co-authored-by: CEU\schielke <Rainer.Schielke@heidelberg.com>
2024-06-03 09:37:40 -04:00
Sean Quinn
98cc1ec344
Allow hex for ip6 literal addr, fix #1800 (#1830)
* Allow hex for ip6 literal addr, fix #1800

* Add UT for ipv6 + Universal client implementation

* add /n at EOF
2024-05-26 08:57:07 -04:00
Vladimír Chlup
25b1e0d906
Tweak CI & fix macOS prefix (#1843)
* Use brew prefix or given one

* Polish CI workflow file
2024-05-26 08:24:29 -04:00
Pavel P
05f9f83240
Avoid unreferenced formal parameter warning in get_range_offset_and_length (#1838)
Release builds result in the following warning because `content_length` param was used only inside asserts:

1> cpp-httplib\httplib.h(4933,45): warning C4100: 'content_length': unreferenced formal parameter
2024-05-17 09:56:06 +09:00
Karen Dombroski
fb739dbaec threadsafe accept on windows, linux
* Windows has WSAAccept() which will create sockets inheriting flags from
  the server socket

* Linux has accept4() which has a flags argument supporting SOCK_CLOEXEC
2024-05-01 21:58:58 +12:00
Karen Dombroski
50fce538c6 threadsafe CLOEXEC on platforms that support it
SOCK_CLOEXEC is a flag available on some platforms to enable creation of
sockets with CLOEXEC already set
2024-05-01 21:46:50 +12:00
Jiwoo Park
3b6597bba9
Fix query parsing when value has = characters (#1822)
* Implement string divider to replace splitter

* Divide query string in half

* Add a test case for query values containing the '=' character

* Add test cases for string divider

* Fix warnings
2024-04-21 19:17:14 -04:00
KTGH
f10720ed69
Move httplibConf.cmake.in & install readme/license (#1826)
* Move httplibConfig.cmake.in to cmake dir

Just makes more sense to put it there I suppose.

* Cmake install README & License

Seems to make sense since you might already do this as a package
manager, or an end user might want them anyways.

The locations are just based on standard Linux locations using
GNUInstallDirs, so it should be sane on other machines too.
2024-04-21 19:14:12 -04:00
rndm13
2bc550b2f0
Added progress to POST, PUT, PATCH and DELETE requests (#1821)
* Added progress to POST, PUT, PATCH, DELETE requests

* Added tests for post, put, patch, delete progress/cancellation

* fix accidental infinite recursion in delete

---------

Co-authored-by: rndm <rndm@localhost.localdomain>
2024-04-21 19:13:41 -04:00
Jiwoo Park
ce36b8a6e5
Highlight notes using markdown features (#1820) 2024-04-18 10:19:54 -04:00
Kent
560854a961
Apply range header base on response status code (#1806)
* Enable ignoring range header to generate customized response

* Apply range header base on response status code
2024-04-11 23:28:21 -04:00
yhirose
2064462c35 Merge branch 'HerrCai0907-fix' 2024-04-11 22:30:00 -04:00
yhirose
07288888ad Code cleanup 2024-04-11 22:26:30 -04:00
yhirose
34d392cf3d Merge branch 'fix' of github.com:HerrCai0907/cpp-httplib into HerrCai0907-fix 2024-04-11 22:22:58 -04:00
yhirose
825c3fbbb1 Removed excess usage of std::move 2024-04-11 21:21:27 -04:00
Rusty Conover
00bdf73ec6
fix: increase default receive buffer to 16kb (#1814)
Since TLS packets have a maximum size of 16kb it makes
sense to fully accommodate them on reads.

Co-authored-by: Rusty Conover <rusty@Juno.local>
2024-04-09 16:59:07 -04:00
Jiwoo Park
f44ab9b3da
Fix range parser when parsing too many ranges (#1812)
* Implement range parser without std::regex

* Add test cases for invalid ranges
2024-04-07 10:06:16 -04:00
Andrea Pappacoda
a61f2b89be
build(meson): generate new test PEMs (#1813)
Follow-up to commits 548dfff0ae and
b8bafbc291
2024-04-07 10:05:07 -04:00
Jiwoo Park
b8bafbc291
Generate missing PEMs for CTest (#1811)
* Generate missing PEMs

* Fix typo

* Copy files using simpler command
2024-04-05 13:50:21 -04:00
yhirose
548dfff0ae Fix #1793 2024-03-09 22:26:17 -05:00
Congcong Cai
4dd2f3d03d fix ambiguous for HandlerWithResponse and Handler in set_error_handler
using lambda expression as Handler in set_error_handler will cause ambiguous.
Template forwarding can forward HandlerWithResponse to the correct overloading function
2024-03-07 19:07:39 +08:00
KTGH
6791a8364d
FindBrotli cleanup & fixes (#1786)
* Unimportant cleanup of FindBrotli

Some whitespace, removal of an unused var, and add a comment about
the missing version support

* Fix incorrect var in FindBrotli

Not much to say, it was just the wrong one. Not sure how that happened,
maybe a holdover from when I did an overhaul at some point..

* Tiny useless edit to FindBrotli

Just a little tweak to how I was postfixing those -static strings to the
lib names. Mostly pointless..

* Simplify some FindBrotli code

Nothing much, just reducing redundant stuff & a cleanup of a comment.

* Ignore PkgConf in FindBrotli if looking for static

As per the issue mentioned in this comment, static PkgConf support
is broken upstream. After testing, I found it'll just accept shared
even if you try to find static, so I'm merely disabling that feature
for this FindBrotli module.

That said, you can still get the static libs if you have them installed,
but PkgConf will be ignored even if found in favor of a regular
find_library call. Otherwise you'd end up with shared libs even if you
ask for static (with PkgConf installed).

TLDR: actually fail correctly when static libs aren't found when PkgConf
thought they were.
2024-02-27 19:25:02 -05:00
KTGH
d1a1c8a158
Add description & URL to Cmake (#1785)
Doesn't do much, but some packages/builders might find a use for these
vars it provides...
2024-02-27 19:22:44 -05:00
yhirose
b4d26badf2 Update github actions 2024-02-17 09:17:51 -05:00
Jiwoo Park
c5a0673c93
Use final keyword for devirtualization (#1779) 2024-02-17 09:17:15 -05:00
Sergey
ad40bd6a00
Implement file mapping for UWP apps (#1775)
Fixes #1773.
2024-02-08 22:59:34 -05:00
yhirose
5c00bbf36b Release v0.15.3 2024-02-05 22:12:43 -05:00
yhirose
9d6f5372a3 Fix #1772 2024-02-05 22:11:53 -05:00
Ikko Eltociear Ashimine
f06fd934f6
Fix typo in gtest-all.cc (#1770)
synthetic -> synthetic
2024-02-05 15:35:33 -05:00
yhirose
80c0cc445e Release v0.15.2 2024-02-02 23:29:30 -05:00
yhirose
762024b890 Fix #1768 2024-02-02 23:17:32 -05:00
yhirose
82a90a2325 Update year 2024-01-29 08:53:01 -05:00
yhirose
b7cac4f4b8 Release v0.15.1 2024-01-29 07:40:56 -05:00
yhirose
e323374d2a Fix #1766 2024-01-28 17:43:51 -05:00
Jiwoo Park
ffc294d37e
Reduce object copy (#1767) 2024-01-28 08:18:29 -05:00
yhirose
fceada9ef4 Changed to return 416 for a request with an invalid range 2024-01-28 08:13:19 -05:00
yhirose
5f0f73fad9 Reduce duplicate computation for ranges 2024-01-27 19:07:52 -05:00
yhirose
530d6ee098 Release v0.15.0 2024-01-27 17:39:58 -05:00
yhirose
420c9759c6 Fix #1694 2024-01-27 16:13:54 -05:00
yhirose
2ce7c22218 Fix #1747 2024-01-27 12:56:39 -05:00
Wander Nauta
4ef9ed80cd
Treat paths with embedded NUL bytes as invalid (#1765)
Fixes #1763.
2024-01-27 08:22:00 -05:00
Jiwoo Park
44b3fe6277
Support move semantics for Response::set_content() (#1764) 2024-01-27 07:53:19 -05:00
Ilya Andreev
449801990f
Add a getter for a bearer token from a request (#1755)
* Add a getter for a bearer token from a request

* Replace a method for bearer token getter with a free function
2024-01-15 08:57:22 -05:00
Jean-Francois Simoneau
af2928d316
Fix select() return code for fd >= 1024 (#1757) 2024-01-15 08:27:31 -05:00
KTGH
d948e38820
Minor cmake fix & cleanup (#1754)
* Reorder cmake docs a bit

Just wanted to group the more related build options together.

Also removed a pointless reference to the old reasoning for the required
min ver since it's 3.14 now anyways.

* Fix outdated cmake comment

We don't use Git to find the version string anymore.
Just updated to match what it's actually used for now.

* Group options and build-tree vars in Cmake

Doesn't really change anything, I just wanted to clean these up a bit.

* Fix how we set HTTPLIB_IS_USING_XXX vars in Cmake

Prevents us acidentally using libs when the user didn't want them
actually used. This could happen if they set the option to OFF but their
own project itself is using the lib, thus we'd find and use it anyways.

Ref #1602 to see an example of this already happening before.
This is merely apply that kind of fix to all 3 of our deps, instead of
just OpenSSL.

* Minor formatting/comment change to Cmake

Pointless, but these things were bothering me..
2024-01-04 18:20:37 -05:00
Matthias Bilger
65218ce222
added missing include of exception (#1752) 2023-12-31 18:59:43 -05:00
Adam Gajda
55e99c4030
Fix -Wold-style-cast warning (#1751) 2023-12-31 18:43:31 -05:00
TheOnlyJoey
b63d50671d
Fixes Windows std::max macro problems (#1750) 2023-12-30 11:37:58 -05:00
yhirose
eba980846b
Fix #1628 (OpenSSL 1.1.1 End of Life on September 11, 2023) (#1745) 2023-12-24 08:20:58 -05:00
vmaffione
374d058de7
ThreadPool: optional limit for jobs queue (#1741)
For very busy servers, the internal jobs queue where accepted
sockets are enqueued can grow without limit.
This is a problem for two reasons:
 - queueing too much work causes the server to respond with huge latency,
   resulting in repetead timeouts on the clients; it is definitely
   better to reject the connection early, so that the client
   receives the backpressure signal as soon as the queue is
   becoming too large
 - the jobs list can eventually cause an out of memory condition
2023-12-24 08:20:22 -05:00
yhirose
31cdcc3c3a Update README about MSYS2 and MinGW 2023-12-23 21:37:34 -05:00
yhirose
ad9f6423e2 Fix #1744 2023-12-23 11:45:08 -05:00
yhirose
cbca63f091 Release v0.14.3 2023-12-21 19:55:25 -05:00
yhirose
b4748a226c Fix #1738 2023-12-21 13:33:52 -05:00
Ilya Andreev
5b943d9bb8
Use StatusCode in tests and examples (#1743)
* Use StatusCode in tests and examples

* Use StatusCode in README
2023-12-20 17:28:57 -05:00
Ilya Andreev
c86f69a105
Use StatusCode in httplib code (#1742) 2023-12-19 22:17:24 -05:00
Ilya Andreev
d39fda0657
Add StatusCode enum (#1739)
* Add StatusCode enum

* Remove changes on RFC 9110

* Add number suffixes to StatusCode constants

* Remove docs for StatusCode constants
2023-12-19 17:57:30 -05:00
Ilya Andreev
37f8dc4382
Change some of status messages based on RFC 9110 (#1740) 2023-12-19 09:22:58 -05:00
yhirose
3a8adda381 Fix #1737 2023-12-17 22:04:36 -05:00
yhirose
8aa38aecaf Fix #1665 2023-12-17 22:03:02 -05:00
yhirose
f1dec77f46 Code format 2023-12-17 22:00:33 -05:00
yhirose
cddaedaff8 Fix #1736 2023-12-15 19:29:54 -05:00
Renato Foot Guimarães Costallat
cefb5a8822
Update README.md (#1731)
Fix "With Progress Callback" code example
2023-12-07 23:21:59 -05:00
davidalo
e426a38c3e
Fix: Query parameter including query delimiter ('?') not being parsed properly (#1713)
* Fix: Query parameter including query delimiter ('?') not being parsed properly

* Add details::split function with and without m argument to allow split parameters with/without counter

* Revert changes in SplitTest.ParseQueryString
2023-12-07 14:28:41 -05:00
yhirose
f14accb7b6 Release v0.14.2 2023-12-04 22:31:12 -05:00
yhirose
c5c704cb3b Fix #1724 2023-12-04 21:34:55 -05:00
Jean-Francois Simoneau
115a786581
Fix readability warnings (#1722)
* Fix readability warnings

Did not fix readbility-qualified-auto, will do a separate pull request

* Revert changes where meaning is lost

* Revert some style changes
2023-11-24 09:55:04 -05:00
Jean-Francois Simoneau
5ef4cfd263
Fix bugprone warnings (#1721) 2023-11-20 22:14:00 -05:00
Jean-Francois Simoneau
03fecb2f78
Fix modernize warnings (#1720) 2023-11-20 22:10:04 -05:00
Jean-Francois Simoneau
7fc8682a0a
Fix performance-noexcept-move-constructor (#1715) 2023-11-20 13:13:59 -05:00
Jiwoo Park
f1431311a4
Minor fixes on test cases (#1709)
* Fix data race

* Replace sleep_for() to wait_until_ready()
2023-11-11 21:28:50 -05:00
Jiwoo Park
1d14e051a5
Remove cryptui on Windows (#1710) 2023-11-11 21:26:57 -05:00
Jiwoo Park
97ae6733ed
Run fuzz test in CTest (#1707) 2023-11-09 19:35:15 -05:00
Jiwoo Park
1d6b22b5f0
Fix C6001 (#1701) 2023-10-30 07:13:40 -04:00
yhirose
1a49076b5b Removed unnecessary exception 2023-10-29 19:36:40 -04:00
Jiwoo Park
d0e4cb3f07
Include missing stdint.h on fuzz test (#1700)
* Include missing stdint.h

* Remove std:: from uint8_t
2023-10-29 19:26:06 -04:00
yhirose
e2813d9d4d Code cleanup. (Removed unnecessary .c_str() calls) 2023-10-23 16:43:12 -04:00
Andrea Pappacoda
20a7f088ce
build(meson): copy 1MB.txt test file (#1695)
Since tests are run in the build directory, the 1MB.txt file has to be
copied there.
2023-10-20 17:58:06 -04:00
yhirose
f63ba7d013 Fix #1685 2023-10-03 09:59:27 -04:00
yhirose
0a629d7391 Release v0.14.1 2023-09-30 22:26:23 -04:00
PabloMK7
a609330e4c
Add optional user defined header writer (#1683)
* Add optional user defined header writer

* Fix errors and add test
2023-09-30 22:13:14 -04:00
Jiwoo Park
c029597a5a
Update the remote address of www.httpwatch.com (#1664) 2023-09-13 10:33:33 -04:00
yhirose
30b7732565 Release v0.14.0 2023-08-22 20:19:07 -04:00
yhirose
6650632e7f Fix #1638 2023-08-22 19:36:10 -04:00
Sven Panne
afe627e7af
Avoid a -Warray-bounds false positive in GCC 13. (#1639)
The exact circumstances when this false positive is triggered are quite
tricky to reproduce, but it happened reproducibly with g++ 13.1 and 13.2 in
a close-source SW I'm working on.  The fix even improves performance by a
very tiny bit: There is no need to copy the std::smatch, having a const
reference is enough.

Just as a side note: -Warray-bounds seems to cause trouble in other
projects, too, so e.g. the Linux kernel has disabled since June 2022.
2023-08-14 10:26:54 -04:00
Duncan Ogilvie
67f6ff7fa9
Fix CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR (#1634) 2023-08-03 17:01:40 -04:00
yhirose
c7ed1796a7 Release v0.13.3 2023-07-31 21:28:33 -04:00
yhirose
44c62d838e
Use memory mapped file for static file server (#1632)
* Use memory mapped file for static file server

* Fix build error
2023-07-31 07:43:50 -04:00
yhirose
6bb580cda8 Fix #1559 2023-07-31 00:27:26 -04:00
yhirose
00a8cb8e5d Code cleanup 2023-07-31 00:22:22 -04:00
yhirose
2e34a39673 Added StaticFileRanges test 2023-07-31 00:22:22 -04:00
yhirose
01b90829bc Removed unnecessary CRLF at the end of multipart ranges data 2023-07-31 00:22:22 -04:00
yhirose
e699bd0730 Release v0.13.2 2023-07-29 12:26:19 -04:00
Akın ELDEN
961a9379d5
Fix #1590 (#1630)
* ClientImpl: Connection=close header control moved from process_request to send_

* Connection=close header control moved from send_ to handle_request

* SSLClient::connect_with_proxy error handling improved

* to_string definition added for Error::ProxyConnection

* Comment improvement

---------

Co-authored-by: akinelden <akin.elden@gmail.com>
2023-07-29 12:09:25 -04:00
yhirose
ec87b04aff Fix #1619 2023-07-29 00:53:57 -04:00
yhirose
aabf752a51 Fix #1519 2023-07-28 23:37:45 -04:00
yhirose
afb0674ccb Fix #1624 2023-07-21 20:36:01 -04:00
bdenhollander
ee625232a4
Fix successful decompress reported as Error::Read (#1612)
* Fix successful decompress reported as Error::Read

Streams less than 4096 bytes are sometimes reported as failed reads because stream_.avail_in is not reduced to 0. The next iteration of the loop finds `prev_avail_in == strm_.avail_in` and return false. `ret = inflate(...)` returns Z_STREAM_END on the first iteration of the loop indicating that inflate is finished. This fix prevents the second iteration of the loop from failing.

* Fix successful decompress reported as Error::Read

- Add unit tests for raw deflate that illustrates the decompression failure when there are extra trailing bytes
2023-07-11 18:35:27 -04:00
Andrea Pappacoda
52d8dd41f1
build(meson): use C++14 with GTest >= 1.13.0 (#1618)
GoogleTest, starting with vesion 1.13.0, requires C++14 to build. This
patch enables C++14 if GoogleTest 1.13.0 or newer is detected when
compiling the tests with Meson, making it possible to use new GTest
versions.

You can find GoogleTest's release notes at
<https://github.com/google/googletest/releases/tag/v1.13.0>.
2023-07-11 18:32:41 -04:00
Alexandre Bouvier
be07d2d7a9
cmake: fix comment (#1616) 2023-07-08 13:24:36 -04:00
yhirose
0f1b62c2b3 Release v0.13.1 2023-07-08 07:41:24 -04:00
yhirose
c30906a541 Code cleanup 2023-07-07 19:43:37 -04:00
bgs99
3533503323
Fix explicit constructor warning (#1614) 2023-07-07 13:17:19 -04:00
yhirose
82acdca638 Release v0.13.0 2023-07-06 18:32:42 -04:00
vmaffione
a1e56a567b
Result: allow default constructor (#1609) 2023-07-05 12:05:29 -04:00
yhirose
0c17d172a2 Code cleanup 2023-07-05 09:06:21 -04:00
yhirose
5d8e7c761f Updated README 2023-07-05 08:45:05 -04:00
bgs99
17fc522b75
Add named path parameters parsing (Implements #1587) (#1608)
* Add named path parameters parsing

* Select match mode based on pattern

* Add examples and comments to README

* Add documentation to matchers
2023-07-05 07:44:19 -04:00
yhirose
f1daa5b88b Fix #1607 2023-07-04 20:27:11 -04:00
yhirose
fe9a1949a6 Fixed an example in README 2023-06-28 11:28:08 -04:00
yhirose
50cba6db9f Fix #1603 2023-06-27 21:23:23 -04:00
Nathan Moinvaziri
18592e7f98
Ability to turn off linking against OpenSSL if already detected. (#1602)
We already detect OpenSSL in our tree for another project, but don't want to
link httplib against OpenSSL or with SSL support.

Allow us to `set(HTTPLIB_IS_USING_OPENSSL FALSE)`.
2023-06-27 20:09:42 -04:00
yhirose
bd9612b81e
Changed to use auto (#1594) 2023-06-17 02:18:34 -04:00
yhirose
7ab5fb65b2
Code cleanup (#1593) 2023-06-16 18:08:28 -04:00
Andre Eisenbach
8df5fedc35
Fix -Wold-style-cast warnings (#1591)
Removed multiple old-style (C) casts and replaced them with the
appropriate _cast's. This makes httplib a better citizen inside projects
that are compiled with all warnings enabled.

Unfortunately one warning remains as a result of invoking an
OpenSSL macro (at least on Linux), that would have to be fixed
upstream.

Also fixed a few casts for invocations of setsockopt.
setsockopt takes a const void* for the value pointer, not a char*.
Well, except on Windows ...

Co-authored-by: Andre Eisenbach <git@4ae.us>
2023-06-16 17:30:24 -04:00
Jiwoo Park
4a61f68fa4
Don't overwrite the last redirected location (#1589)
* Don't overwrite the last redirected location

* Check the last redirected location
2023-06-16 14:56:16 -04:00
Jiwoo Park
067890133c
Use nghttp2-hosted httpbin.org (#1586)
* Use nghttp2-hosted httpbin.org

* Add CPPHTTPLIB_DEFAULT_HTTPBIN macro to choose the default httpbin.org
2023-06-15 11:12:41 -04:00
yhirose
d3076f5a70 v0.12.6 2023-06-10 07:02:38 +09:00
yhirose
ed129f057f Fixed C++11 warnings and code format 2023-06-09 20:49:46 +09:00
Jiwoo Park
eab5ea01d7
Load in-memory CA certificates (#1579)
* Load in-memory CA certs

* Add test cases for in-memory cert loading

* Don't use the IIFE style
2023-06-09 16:34:51 +09:00
Petr Hosek
3e287b3a26
Provide a CMake option to disable C++ exceptions (#1580)
This allows disabling the use of C++ exceptions at CMake configure time.
The value is encoded in the generated httplibTargets.cmake file and will
be used by CMake projects that import it.
2023-06-06 16:56:26 +09:00
v1gnesh
4f33637b43
Add support for zOS (#1581)
Signed-off-by: v1gnesh <v1gnesh@users.noreply.github.com>
2023-06-06 14:14:06 +09:00
db-src
698a1e51ec
Move, not copy, Logger and Handler functors (#1576)
* Explicitly #include <utility> for use of std::move

* Move not copy Logger arg from Client to ClientImpl

* Move not copy, set_error_handler Handler to lambda

* Remove null statement in non-empty if/else block

I guess it was a relic from a time before the other statement was added.

---------

Co-authored-by: Daniel Boles <daniel.boles@voltalis.com>
2023-06-02 15:40:00 +09:00
48 changed files with 39407 additions and 2056 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
/test/www*/dir/*.html text eol=lf
/test/www*/dir/*.txt text eol=lf

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,41 +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:
build:
runs-on: ${{ matrix.os }}
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: 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
- 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
- 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:
os: [macOS-latest, ubuntu-latest, windows-latest]
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
if: matrix.os == 'windows-latest'
- name: Prepare Git for Checkout on Windows
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: checkout
uses: actions/checkout@v3
- name: install brotli library on ubuntu
if: matrix.os == 'ubuntu-latest'
run: sudo apt update && sudo apt-get install -y libbrotli-dev
- name: install brotli library on macOS
if: matrix.os == 'macOS-latest'
run: brew install brotli
- name: make
if: matrix.os != 'windows-latest'
run: cd test && make -j2
- name: check fuzz test target
if: matrix.os == 'ubuntu-latest'
run: cd test && make fuzz_test
- name: setup msbuild on windows
if: matrix.os == 'windows-latest'
uses: microsoft/setup-msbuild@v1.1
- name: make-windows
if: matrix.os == 'windows-latest'
run: |
cd test
msbuild.exe test.sln /verbosity:minimal /t:Build "/p:Configuration=Release;Platform=x64"
x64\Release\test.exe
- name: Checkout
uses: actions/checkout@v4
- 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: 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"

8
.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,9 +23,13 @@ test/test.xcodeproj/*/xcuser*
test/*.o
test/*.pem
test/*.srl
test/_build_*
work/
benchmark/server*
*.swp
build/
Debug
Release
*.vcxproj.user
@ -33,5 +39,7 @@ Release
*.db
ipch
*.dSYM
*.pyc
.*
!/.gitattributes
!/.travis.yml

View File

@ -3,11 +3,11 @@
* BUILD_SHARED_LIBS (default off) builds as a shared library (if HTTPLIB_COMPILE is ON)
* HTTPLIB_USE_OPENSSL_IF_AVAILABLE (default on)
* HTTPLIB_USE_ZLIB_IF_AVAILABLE (default on)
* HTTPLIB_USE_BROTLI_IF_AVAILABLE (default on)
* HTTPLIB_REQUIRE_OPENSSL (default off)
* HTTPLIB_REQUIRE_ZLIB (default off)
* HTTPLIB_USE_BROTLI_IF_AVAILABLE (default on)
* HTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN (default on)
* HTTPLIB_REQUIRE_BROTLI (default off)
* HTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN (default on)
* HTTPLIB_COMPILE (default off)
* HTTPLIB_INSTALL (default on)
* HTTPLIB_TEST (default off)
@ -59,7 +59,6 @@
-------------------------------------------------------------------------------
FindPython3 requires Cmake v3.12
ARCH_INDEPENDENT option of write_basic_package_version_file() requires Cmake v3.14
]]
cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
@ -69,16 +68,24 @@ cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR)
# This is so the maintainer doesn't actually need to update this manually.
file(STRINGS httplib.h _raw_version_string REGEX "CPPHTTPLIB_VERSION \"([0-9]+\\.[0-9]+\\.[0-9]+)\"")
# Needed since git tags have "v" prefixing them.
# Also used if the fallback to user agent string is being used.
# Extracts just the version string itself from the whole string contained in _raw_version_string
# since _raw_version_string would contain the entire line of code where it found the version string
string(REGEX MATCH "([0-9]+\\.?)+" _httplib_version "${_raw_version_string}")
project(httplib VERSION ${_httplib_version} LANGUAGES CXX)
project(httplib
VERSION ${_httplib_version}
LANGUAGES CXX
DESCRIPTION "A C++ header-only HTTP/HTTPS server and client library."
HOMEPAGE_URL "https://github.com/yhirose/cpp-httplib"
)
# Change as needed to set an OpenSSL minimum version.
# This is used in the installed Cmake config file.
set(_HTTPLIB_OPENSSL_MIN_VER "1.1.1")
set(_HTTPLIB_OPENSSL_MIN_VER "3.0.0")
# Lets you disable C++ exception during CMake configure time.
# The value is used in the install CMake config file.
option(HTTPLIB_NO_EXCEPTIONS "Disable the use of C++ exceptions" OFF)
# Allow for a build to require OpenSSL to pass, instead of just being optional
option(HTTPLIB_REQUIRE_OPENSSL "Requires OpenSSL to be found & linked, or fails build." OFF)
option(HTTPLIB_REQUIRE_ZLIB "Requires ZLIB to be found & linked, or fails build." OFF)
@ -90,10 +97,6 @@ option(HTTPLIB_USE_ZLIB_IF_AVAILABLE "Uses ZLIB (if available) to enable Zlib co
option(HTTPLIB_COMPILE "If ON, uses a Python script to split the header into a compilable header & source file (requires Python v3)." OFF)
# Lets you disable the installation (useful when fetched from another CMake project)
option(HTTPLIB_INSTALL "Enables the installation target" ON)
# Just setting this variable here for people building in-tree
if(HTTPLIB_COMPILE)
set(HTTPLIB_IS_COMPILED TRUE)
endif()
option(HTTPLIB_TEST "Enables testing and builds tests" OFF)
option(HTTPLIB_REQUIRE_BROTLI "Requires Brotli to be found & linked, or fails build." OFF)
option(HTTPLIB_USE_BROTLI_IF_AVAILABLE "Uses Brotli (if available) to enable Brotli decompression support." ON)
@ -106,45 +109,48 @@ if (BUILD_SHARED_LIBS AND WIN32 AND HTTPLIB_COMPILE)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
# Set some variables that are used in-tree and while building based on our options
set(HTTPLIB_IS_COMPILED ${HTTPLIB_COMPILE})
set(HTTPLIB_IS_USING_CERTS_FROM_MACOSX_KEYCHAIN ${HTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN})
# Threads needed for <thread> on some systems, and for <pthread.h> on Linux
set(THREADS_PREFER_PTHREAD_FLAG true)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
# Since Cmake v3.11, Crypto & SSL became optional when not specified as COMPONENTS.
if(HTTPLIB_REQUIRE_OPENSSL)
find_package(OpenSSL ${_HTTPLIB_OPENSSL_MIN_VER} COMPONENTS Crypto SSL REQUIRED)
set(HTTPLIB_IS_USING_OPENSSL TRUE)
elseif(HTTPLIB_USE_OPENSSL_IF_AVAILABLE)
find_package(OpenSSL ${_HTTPLIB_OPENSSL_MIN_VER} COMPONENTS Crypto SSL QUIET)
endif()
# Just setting this variable here for people building in-tree
if(OPENSSL_FOUND)
set(HTTPLIB_IS_USING_OPENSSL TRUE)
# Avoid a rare circumstance of not finding all components but the end-user did their
# own call for OpenSSL, which might trick us into thinking we'd otherwise have what we wanted
if (TARGET OpenSSL::SSL AND TARGET OpenSSL::Crypto)
set(HTTPLIB_IS_USING_OPENSSL ${OPENSSL_FOUND})
else()
set(HTTPLIB_IS_USING_OPENSSL FALSE)
endif()
endif()
if(HTTPLIB_REQUIRE_ZLIB)
find_package(ZLIB REQUIRED)
set(HTTPLIB_IS_USING_ZLIB TRUE)
elseif(HTTPLIB_USE_ZLIB_IF_AVAILABLE)
find_package(ZLIB QUIET)
endif()
# Just setting this variable here for people building in-tree
# FindZLIB doesn't have a ZLIB_FOUND variable, so check the target.
if(TARGET ZLIB::ZLIB)
set(HTTPLIB_IS_USING_ZLIB TRUE)
# FindZLIB doesn't have a ZLIB_FOUND variable, so check the target.
if(TARGET ZLIB::ZLIB)
set(HTTPLIB_IS_USING_ZLIB TRUE)
endif()
endif()
# Adds our cmake folder to the search path for find_package
# This is so we can use our custom FindBrotli.cmake
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if(HTTPLIB_REQUIRE_BROTLI)
find_package(Brotli COMPONENTS encoder decoder common REQUIRED)
set(HTTPLIB_IS_USING_BROTLI TRUE)
elseif(HTTPLIB_USE_BROTLI_IF_AVAILABLE)
find_package(Brotli COMPONENTS encoder decoder common QUIET)
endif()
# Just setting this variable here for people building in-tree
if(Brotli_FOUND)
set(HTTPLIB_IS_USING_BROTLI TRUE)
endif()
if(HTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN)
set(HTTPLIB_IS_USING_CERTS_FROM_MACOSX_KEYCHAIN TRUE)
set(HTTPLIB_IS_USING_BROTLI ${Brotli_FOUND})
endif()
# Used for default, common dirs that the end-user can change (if needed)
@ -188,6 +194,7 @@ if(HTTPLIB_COMPILE)
PROPERTIES
VERSION ${${PROJECT_NAME}_VERSION}
SOVERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}"
OUTPUT_NAME cpp-httplib
)
else()
# This is for header-only.
@ -200,9 +207,7 @@ endif()
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
# Require C++11
target_compile_features(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
cxx_std_11
)
target_compile_features(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC} cxx_std_11)
target_include_directories(${PROJECT_NAME} SYSTEM ${_INTERFACE_OR_PUBLIC}
$<BUILD_INTERFACE:${_httplib_build_includedir}>
@ -215,7 +220,6 @@ target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
# Needed for Windows libs on Mingw, as the pragma comment(lib, "xyz") aren't triggered.
$<$<PLATFORM_ID:Windows>:ws2_32>
$<$<PLATFORM_ID:Windows>:crypt32>
$<$<PLATFORM_ID:Windows>:cryptui>
# Needed for API from MacOS Security framework
"$<$<AND:$<PLATFORM_ID:Darwin>,$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>,$<BOOL:${HTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN}>>:-framework CoreFoundation -framework Security>"
# Can't put multiple targets in a single generator expression or it bugs out.
@ -229,6 +233,7 @@ target_link_libraries(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
# Set the definitions to enable optional features
target_compile_definitions(${PROJECT_NAME} ${_INTERFACE_OR_PUBLIC}
$<$<BOOL:${HTTPLIB_NO_EXCEPTIONS}>:CPPHTTPLIB_NO_EXCEPTIONS>
$<$<BOOL:${HTTPLIB_IS_USING_BROTLI}>:CPPHTTPLIB_BROTLI_SUPPORT>
$<$<BOOL:${HTTPLIB_IS_USING_ZLIB}>:CPPHTTPLIB_ZLIB_SUPPORT>
$<$<BOOL:${HTTPLIB_IS_USING_OPENSSL}>:CPPHTTPLIB_OPENSSL_SUPPORT>
@ -241,7 +246,7 @@ set(_TARGET_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
include(CMakePackageConfigHelpers)
# Configures the meta-file httplibConfig.cmake.in to replace variables with paths/values/etc.
configure_package_config_file("${PROJECT_NAME}Config.cmake.in"
configure_package_config_file("cmake/${PROJECT_NAME}Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION "${_TARGET_INSTALL_CMAKEDIR}"
# Passes the includedir install path
@ -251,13 +256,13 @@ configure_package_config_file("${PROJECT_NAME}Config.cmake.in"
if(HTTPLIB_COMPILE)
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
# Example: if you find_package(httplib 0.5.4)
# then anything >= 0.5 and <= 1.0 is accepted
# then anything >= 0.5.4 and < 0.6 is accepted
COMPATIBILITY SameMinorVersion
)
else()
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
# Example: if you find_package(httplib 0.5.4)
# then anything >= 0.5 and <= 1.0 is accepted
# then anything >= 0.5.4 and < 0.6 is accepted
COMPATIBILITY SameMinorVersion
# Tells Cmake that it's a header-only lib
# Mildly useful for end-users :)
@ -269,9 +274,7 @@ if(HTTPLIB_INSTALL)
# Creates the export httplibTargets.cmake
# This is strictly what holds compilation requirements
# and linkage information (doesn't find deps though).
install(TARGETS ${PROJECT_NAME}
EXPORT httplibTargets
)
install(TARGETS ${PROJECT_NAME} EXPORT httplibTargets)
install(FILES "${_httplib_build_includedir}/httplib.h" TYPE INCLUDE)
@ -291,6 +294,13 @@ if(HTTPLIB_INSTALL)
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${_TARGET_INSTALL_CMAKEDIR}
)
# Install documentation & license
# 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)

11
Dockerfile Normal file
View File

@ -0,0 +1,11 @@
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. main.cc && strip server
FROM scratch
COPY --from=builder /build/server /server
COPY docker/html/index.html /html/index.html
EXPOSE 80
CMD ["/server"]

190
README.md
View File

@ -7,7 +7,8 @@ A C++11 single-file header-only cross platform HTTP/HTTPS library.
It's extremely easy to setup. Just include the **httplib.h** file in your code!
NOTE: This library uses 'blocking' socket I/O. If you are looking for a library with 'non-blocking' socket I/O, this is not the one that you want.
> [!IMPORTANT]
> This library uses 'blocking' socket I/O. If you are looking for a library with 'non-blocking' socket I/O, this is not the one that you want.
Simple examples
---------------
@ -38,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;
@ -53,9 +54,11 @@ SSL Support
SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked.
NOTE: cpp-httplib currently supports only version 1.1.1 and 3.0.
> [!NOTE]
> cpp-httplib currently supports only version 3.0 or later. Please see [this page](https://www.openssl.org/policies/releasestrat.html) to get more information.
NOTE for macOS: cpp-httplib now can use system certs with `CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN`. `CoreFoundation` and `Security` should be linked with `-framework`.
> [!TIP]
> For macOS: cpp-httplib now can use system certs with `CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN`. `CoreFoundation` and `Security` should be linked with `-framework`.
```c++
#define CPPHTTPLIB_OPENSSL_SUPPORT
@ -74,9 +77,13 @@ 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: When using SSL, it seems impossible to avoid SIGPIPE in all cases, since on some operating systems, SIGPIPE can only be suppressed on a per-message basis, but there is no way to make the OpenSSL library do so for its internal communications. If your program needs to avoid being terminated on SIGPIPE, the only fully general way might be to set up a signal handler for SIGPIPE to handle or ignore it yourself.
> [!NOTE]
> When using SSL, it seems impossible to avoid SIGPIPE in all cases, since on some operating systems, SIGPIPE can only be suppressed on a per-message basis, but there is no way to make the OpenSSL library do so for its internal communications. If your program needs to avoid being terminated on SIGPIPE, the only fully general way might be to set up a signal handler for SIGPIPE to handle or ignore it yourself.
Server
------
@ -94,11 +101,20 @@ int main(void)
res.set_content("Hello World!", "text/plain");
});
// Match the request path against a regular expression
// and extract its captures
svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
auto numbers = req.matches[1];
res.set_content(numbers, "text/plain");
});
// Capture the second segment of the request path as "id" path param
svr.Get("/users/:id", [&](const Request& req, Response& res) {
auto user_id = req.path_params.at("id");
res.set_content(user_id, "text/plain");
});
// Extract values from HTTP headers and URL query params
svr.Get("/body-header-param", [](const Request& req, Response& res) {
if (req.has_header("Content-Length")) {
auto val = req.get_header_value("Content-Length");
@ -109,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();
});
@ -181,6 +212,9 @@ The followings are built-in mappings:
| webm | video/webm | zip | application/zip |
| mp3 | audio/mp3 | wasm | application/wasm |
> [!WARNING]
> These static file server methods are not thread-safe.
### File request handler
```cpp
@ -190,8 +224,6 @@ svr.set_file_request_handler([](const Request &req, Response &res) {
});
```
NOTE: These static file server methods are not thread-safe.
### Logging
```cpp
@ -226,11 +258,12 @@ svr.set_exception_handler([](const auto& req, auto& res, std::exception_ptr ep)
snprintf(buf, sizeof(buf), fmt, "Unknown Exception");
}
res.set_content(buf, "text/html");
res.status = 500;
res.status = StatusCode::InternalServerError_500;
});
```
NOTE: if you don't provide the `catch (...)` block for a rethrown exception pointer, an uncaught exception will end up causing the server crash. Be careful!
> [!CAUTION]
> if you don't provide the `catch (...)` block for a rethrown exception pointer, an uncaught exception will end up causing the server crash. Be careful!
### Pre routing handler
@ -303,7 +336,7 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
res.set_content_provider(
data->size(), // Content length
"text/plain", // Content type
[data](size_t offset, size_t length, DataSink &sink) {
[&, data](size_t offset, size_t length, DataSink &sink) {
const auto &d = *data;
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
return true; // return 'false' if you want to cancel the process.
@ -369,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.
@ -376,14 +421,14 @@ By default, the server sends a `100 Continue` response for an `Expect: 100-conti
```cpp
// Send a '417 Expectation Failed' response.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
return 417;
return StatusCode::ExpectationFailed_417;
});
```
```cpp
// Send a final status without reading the message body.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
return res.status = 401;
return res.status = StatusCode::Unauthorized_401;
});
```
@ -408,13 +453,16 @@ svr.set_idle_interval(0, 100000); // 100 milliseconds
svr.set_payload_max_length(1024 * 1024 * 512); // 512MB
```
> [!NOTE]
> When the request body content type is 'www-form-urlencoded', the actual payload length shouldn't exceed `CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH`.
### Server-Sent Events
Please see [Server example](https://github.com/yhirose/cpp-httplib/blob/master/example/ssesvr.cc) and [Client example](https://github.com/yhirose/cpp-httplib/blob/master/example/ssecli.cc).
### 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.
@ -422,6 +470,17 @@ If you want to set the thread count at runtime, there is no convenient way... Bu
svr.new_task_queue = [] { return new ThreadPool(12); };
```
You can also provide an optional parameter to limit the maximum number
of pending requests, i.e. requests `accept()`ed by the listener but
still waiting to be serviced by worker threads.
```cpp
svr.new_task_queue = [] { return new ThreadPool(/*num_threads=*/12, /*max_queued_requests=*/18); };
```
Default limit is 0 (unlimited). Once the limit is reached, the listener
will shutdown the client connection.
### Override the default thread pool with yours
You can supply your own thread pool implementation according to your need.
@ -433,8 +492,10 @@ public:
pool_.start_with_thread_count(n);
}
virtual void enqueue(std::function<void()> fn) override {
pool_.enqueue(fn);
virtual bool enqueue(std::function<void()> fn) override {
/* Return true if the task was actually enqueued, or false
* if the caller must drop the corresponding connection. */
return pool_.enqueue(fn);
}
virtual void shutdown() override {
@ -462,7 +523,7 @@ int main(void)
httplib::Client cli("localhost", 1234);
if (auto res = cli.Get("/hi")) {
if (res->status == 200) {
if (res->status == StatusCode::OK_200) {
std::cout << res->body << std::endl;
}
} else {
@ -472,7 +533,8 @@ int main(void)
}
```
NOTE: Constructor with scheme-host-port string is now supported!
> [!TIP]
> Constructor with scheme-host-port string is now supported!
```c++
httplib::Client cli("localhost");
@ -510,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");
```
@ -592,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
@ -612,7 +677,7 @@ std::string body;
auto res = cli.Get(
"/stream", Headers(),
[&](const Response &response) {
EXPECT_EQ(200, response.status);
EXPECT_EQ(StatusCode::OK_200, response.status);
return true; // return 'false' if you want to cancel the request.
},
[&](const char *data, size_t data_length) {
@ -653,7 +718,7 @@ auto res = cli.Post(
### With Progress Callback
```cpp
httplib::Client client(url, port);
httplib::Client cli(url, port);
// prints: 0 / 000 bytes => 50% complete
auto res = cli.Get("/", [](uint64_t len, uint64_t total) {
@ -680,7 +745,8 @@ cli.set_digest_auth("user", "pass");
cli.set_bearer_token_auth("token");
```
NOTE: OpenSSL is required for Digest Authentication.
> [!NOTE]
> OpenSSL is required for Digest Authentication.
### Proxy server support
@ -697,7 +763,8 @@ cli.set_proxy_digest_auth("user", "pass");
cli.set_proxy_bearer_token_auth("pass");
```
NOTE: OpenSSL is required for Digest Authentication.
> [!NOTE]
> OpenSSL is required for Digest Authentication.
### Range
@ -746,7 +813,8 @@ res->status; // 200
### Use a specific network interface
NOTE: This feature is not available on Windows, yet.
> [!NOTE]
> This feature is not available on Windows, yet.
```cpp
cli.set_interface("eth0"); // Interface name, IP address or host name
@ -773,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++
@ -784,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
@ -813,6 +909,32 @@ $ ./split.py
Wrote out/httplib.h and out/httplib.cc
```
Dockerfile for Static HTTP Server
---------------------------------
Dockerfile for static HTTP server is available. Port number of this HTTP server is 80, and it serves static files from `/html` directory in the container.
```bash
> docker build -t 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 ..."
192.168.65.1 - - [31/Aug/2024:21:34:26 +0000] "GET /favicon.ico HTTP/1.1" 404 152 "-" "Mozilla/5.0 ..."
```
NOTE
----
@ -835,14 +957,16 @@ Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32
#include <httplib.h>
```
NOTE: 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]
> 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 on Windows are not supported.
> [!NOTE]
> Windows 8 or lower, Visual Studio 2015 or lower, and Cygwin and MSYS2 including MinGW are neither supported nor tested.
License
-------
MIT license (© 2023 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,6 +1,6 @@
# A simple FindBrotli package for Cmake's find_package function.
# Note: This find package doesn't have version support, as the version file doesn't seem to be installed on most systems.
#
#
# If you want to find the static packages instead of shared (the default), define BROTLI_USE_STATIC_LIBS as TRUE.
# The targets will have the same names, but it will use the static libs.
#
@ -14,7 +14,7 @@
# If they asked for a specific version, warn/fail since we don't support it.
# TODO: if they start distributing the version somewhere, implement finding it.
# But currently there's a version header that doesn't seem to get installed.
# See https://github.com/google/brotli/issues/773#issuecomment-579133187
if(Brotli_FIND_VERSION)
set(_brotli_version_error_msg "FindBrotli.cmake doesn't have version support!")
# If the package is required, throw a fatal error
@ -68,29 +68,24 @@ if(BROTLI_USE_STATIC_LIBS)
set(_brotli_stat_str "_STATIC")
endif()
# Lets us know we are using the PkgConfig libraries
# Will be set false if any non-pkgconf vars are used
set(_brotli_using_pkgconf TRUE)
# Each string here is "ComponentName;LiteralName" (the semi-colon is a delimiter)
foreach(_listvar "common;common" "decoder;dec" "encoder;enc")
# Split the component name and literal library name from the listvar
list(GET _listvar 0 _component_name)
list(GET _listvar 1 _libname)
if(PKG_CONFIG_FOUND)
# NOTE: We can't rely on PkgConf for static libs since the upstream static lib support is broken
# See https://github.com/google/brotli/issues/795
# TODO: whenever their issue is fixed upstream, remove this "AND NOT BROTLI_USE_STATIC_LIBS" check
if(PKG_CONFIG_FOUND AND NOT BROTLI_USE_STATIC_LIBS)
# These need to be GLOBAL for MinGW when making ALIAS libraries against them.
if(BROTLI_USE_STATIC_LIBS)
# Have to use _STATIC to tell PkgConfig to find the static libs.
pkg_check_modules(Brotli_${_component_name}_STATIC QUIET GLOBAL IMPORTED_TARGET libbrotli${_libname})
else()
pkg_check_modules(Brotli_${_component_name} QUIET GLOBAL IMPORTED_TARGET libbrotli${_libname})
endif()
# Have to postfix _STATIC on the name to tell PkgConfig to find the static libs.
pkg_check_modules(Brotli_${_component_name}${_brotli_stat_str} QUIET GLOBAL IMPORTED_TARGET libbrotli${_libname})
endif()
# Check if the target was already found by Pkgconf
if(TARGET PkgConfig::Brotli_${_component_name} OR TARGET PkgConfig::Brotli_${_component_name}_STATIC)
# Can't use generators for ALIAS targets, so you get this jank
# Check if the target was already found by Pkgconf
if(TARGET PkgConfig::Brotli_${_component_name}${_brotli_stat_str})
# ALIAS since we don't want the PkgConfig namespace on the Cmake library (for end-users)
add_library(Brotli::${_component_name} ALIAS PkgConfig::Brotli_${_component_name}${_brotli_stat_str})
# Tells HANDLE_COMPONENTS we found the component
@ -109,23 +104,18 @@ foreach(_listvar "common;common" "decoder;dec" "encoder;enc")
continue()
endif()
# Lets us know we aren't using the PkgConfig libraries
set(_brotli_using_pkgconf FALSE)
if(Brotli_FIND_REQUIRED_${_component_name})
# If it's required, we can set the name used in find_library as a required var for FindPackageHandleStandardArgs
list(APPEND _brotli_req_vars "Brotli_${_component_name}")
endif()
list(APPEND _brotli_lib_names
"brotli${_libname}"
"libbrotli${_libname}"
)
if(BROTLI_USE_STATIC_LIBS)
list(APPEND _brotli_lib_names
"brotli${_libname}-static"
"libbrotli${_libname}-static"
)
else()
list(APPEND _brotli_lib_names
"brotli${_libname}"
"libbrotli${_libname}"
)
# Postfix "-static" to the libnames since we're looking for static libs
list(TRANSFORM _brotli_lib_names APPEND "-static")
endif()
find_library(Brotli_${_component_name}
@ -168,7 +158,7 @@ find_package_handle_standard_args(Brotli
Brotli_FOUND
REQUIRED_VARS
Brotli_INCLUDE_DIR
${_brotli_required_targets}
${_brotli_req_vars}
HANDLE_COMPONENTS
)

7
docker-compose.yml Normal file
View File

@ -0,0 +1,7 @@
services:
http:
build: .
ports:
- "8080:80"
volumes:
- ./docker/html:/html

21
docker/html/index.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome to cpp-httplib!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to cpp-httplib!</h1>
<p>If you see this page, the cpp-httplib web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="https://github.com/yhirose/cpp-httplib">github.com/yhirose/cpp-httplib</a>.<br/>
<p><em>Thank you for using cpp-httplib.</em></p>
</body>
</html>

81
docker/main.cc Normal file
View File

@ -0,0 +1,81 @@
//
// main.cc
//
// Copyright (c) 2025 Yuji Hirose. All rights reserved.
// MIT License
//
#include <chrono>
#include <ctime>
#include <format>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <httplib.h>
constexpr auto error_html = R"(<html>
<head><title>{} {}</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>cpp-httplib/{}</center>
</body>
</html>
)";
void sigint_handler(int s) { exit(1); }
std::string time_local() {
auto p = std::chrono::system_clock::now();
auto t = std::chrono::system_clock::to_time_t(p);
std::stringstream ss;
ss << std::put_time(std::localtime(&t), "%d/%b/%Y:%H:%M:%S %z");
return ss.str();
}
std::string log(auto &req, auto &res) {
auto remote_user = "-"; // TODO:
auto request = std::format("{} {} {}", req.method, req.path, req.version);
auto body_bytes_sent = res.get_header_value("Content-Length");
auto http_referer = "-"; // TODO:
auto http_user_agent = req.get_header_value("User-Agent", "-");
// 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"';
return std::format(R"({} - {} [{}] "{}" {} {} "{}" "{}")", req.remote_addr,
remote_user, time_local(), request, res.status,
body_bytes_sent, http_referer, http_user_agent);
}
int main(int argc, const char **argv) {
signal(SIGINT, sigint_handler);
auto base_dir = "./html";
auto host = "0.0.0.0";
auto port = 80;
httplib::Server svr;
svr.set_error_handler([](auto & /*req*/, auto &res) {
auto body =
std::format(error_html, res.status, httplib::status_message(res.status),
CPPHTTPLIB_VERSION);
res.set_content(body, "text/html");
});
svr.set_logger(
[](auto &req, auto &res) { std::cout << log(req, res) << std::endl; });
svr.set_mount_point("/", base_dir);
std::cout << std::format("Serving HTTP on {0} port {1} ...", host, port)
<< std::endl;
auto ret = svr.listen(host, port);
return ret ? 0 : 1;
}

View File

@ -1,11 +1,9 @@
#CXX = clang++
CXXFLAGS = -O2 -std=c++11 -I.. -Wall -Wextra -pthread
PREFIX = /usr/local
#PREFIX = $(shell brew --prefix)
PREFIX ?= $(shell brew --prefix)
OPENSSL_DIR = $(PREFIX)/opt/openssl@1.1
#OPENSSL_DIR = $(PREFIX)/opt/openssl@3
OPENSSL_DIR = $(PREFIX)/opt/openssl@3
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
ifneq ($(OS), Windows_NT)
@ -20,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)
@ -52,9 +50,15 @@ ssecli : ssecli.cc ../httplib.h Makefile
benchmark : benchmark.cc ../httplib.h Makefile
$(CXX) -o benchmark $(CXXFLAGS) benchmark.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT)
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 *.pem
rm server client hello simplecli simplesvr upload redirect ssesvr ssecli benchmark one_time_request server_and_client *.pem

View File

@ -26,7 +26,7 @@ int main(void) {
for (int i = 0; i < 3; i++) {
StopWatch sw(to_string(i).c_str());
auto res = cli.Post("/post", body, "application/octet-stream");
assert(res->status == 200);
assert(res->status == httplib::StatusCode::OK_200);
}
return 0;

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

@ -0,0 +1,56 @@
#include <httplib.h>
#include <iostream>
using namespace httplib;
const char *HOST = "localhost";
const int PORT = 1234;
void one_time_request_server(const char *label) {
std::thread th;
Server svr;
svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
res.set_content(std::string("Hello from ") + label, "text/plain");
// Stop server
th = std::thread([&]() { svr.stop(); });
});
svr.listen(HOST, PORT);
th.join();
std::cout << label << " ended..." << std::endl;
}
void send_request(const char *label) {
Client cli(HOST, PORT);
std::cout << "Send " << label << " request" << std::endl;
auto res = cli.Get("/hi");
if (res) {
std::cout << res->body << std::endl;
} else {
std::cout << "Request error: " + to_string(res.error()) << std::endl;
}
}
int main(void) {
auto th1 = std::thread([&]() { one_time_request_server("Server #1"); });
auto th2 = std::thread([&]() { one_time_request_server("Server #2"); });
std::this_thread::sleep_for(std::chrono::milliseconds(100));
send_request("1st");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
send_request("2nd");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
send_request("3rd");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
th1.join();
th2.join();
}

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_);

3983
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
@ -30,7 +30,7 @@ endif
deps = [dependency('threads')]
args = []
openssl_dep = dependency('openssl', version: '>=1.1.1', required: get_option('cpp-httplib_openssl'))
openssl_dep = dependency('openssl', version: '>=3.0.0', required: get_option('cpp-httplib_openssl'))
if openssl_dep.found()
deps += openssl_dep
args += '-DCPPHTTPLIB_OPENSSL_SUPPORT'
@ -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

@ -2,7 +2,7 @@ find_package(GTest)
if(GTest_FOUND)
if(NOT TARGET GTest::gtest_main AND TARGET GTest::Main)
# CMake <3.20
# CMake <3.20
add_library(GTest::gtest_main INTERFACE IMPORTED)
target_link_libraries(GTest::gtest_main INTERFACE GTest::Main)
endif()
@ -24,22 +24,24 @@ 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)
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/www www
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/www2 www2
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/www3 www3
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_LIST_DIR}/ca-bundle.crt ca-bundle.crt
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_LIST_DIR}/image.jpg image.jpg
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND_ERROR_IS_FATAL ANY
file(
COPY www www2 www3 ca-bundle.crt image.jpg
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
)
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
@ -59,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
)
@ -70,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
@ -101,4 +103,19 @@ if(HTTPLIB_IS_USING_OPENSSL)
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND_ERROR_IS_FATAL ANY
)
execute_process(
COMMAND ${OPENSSL_COMMAND} genrsa -aes256 -passout pass:test012! 2048
OUTPUT_FILE client_encrypted.key.pem
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND_ERROR_IS_FATAL ANY
)
execute_process(
COMMAND ${OPENSSL_COMMAND} req -new -batch -config ${CMAKE_CURRENT_LIST_DIR}/test.conf -key client_encrypted.key.pem -passin pass:test012!
COMMAND ${OPENSSL_COMMAND} x509 -days 370 -req -CA rootCA.cert.pem -CAkey rootCA.key.pem -CAcreateserial
OUTPUT_FILE client_encrypted.cert.pem
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND_ERROR_IS_FATAL ANY
)
endif()
add_subdirectory(fuzzing)

View File

@ -1,11 +1,9 @@
CXX = clang++
CXXFLAGS = -g -std=c++11 -I. -Wall -Wextra -Wtype-limits -Wconversion -Wshadow # -fno-exceptions -DCPPHTTPLIB_NO_EXCEPTIONS -fsanitize=address
PREFIX = /usr/local
#PREFIX = $(shell brew --prefix)
PREFIX ?= $(shell brew --prefix)
OPENSSL_DIR = $(PREFIX)/opt/openssl@1.1
#OPENSSL_DIR = $(PREFIX)/opt/openssl@3
OPENSSL_DIR = $(PREFIX)/opt/openssl@3
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
ifneq ($(OS), Windows_NT)
@ -20,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
@ -30,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
@ -44,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)
@ -65,16 +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
#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

@ -0,0 +1,10 @@
file(GLOB HTTPLIB_CORPUS corpus/*)
add_executable(httplib-test-fuzz
server_fuzzer.cc
standalone_fuzz_target_runner.cpp
)
target_link_libraries(httplib-test-fuzz PRIVATE httplib)
add_test(
NAME httplib-test-fuzz
COMMAND httplib-test-fuzz ${HTTPLIB_CORPUS}
)

View File

@ -1,5 +1,6 @@
#include <cstdint>
#include <httplib.h>
#include <memory>
class FuzzedStream : public httplib::Stream {
public:
@ -24,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";
@ -38,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_;
@ -49,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);
}
};

View File

@ -5,9 +5,9 @@
// on the test corpus or on a single file,
// e.g. the one that comes from a bug report.
#include <cassert>
#include <iostream>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <vector>
// Forward declare the "fuzz target" interface.
@ -21,7 +21,7 @@ int main(int argc, char **argv) {
std::ifstream in(argv[i]);
in.seekg(0, in.end);
size_t length = static_cast<size_t>(in.tellg());
in.seekg (0, in.beg);
in.seekg(0, in.beg);
std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
// Allocate exactly length bytes so that we reliably catch buffer overflows.
std::vector<char> bytes(length);

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

@ -1912,7 +1912,7 @@ void AssertHelper::operator=(const Message& message) const {
namespace {
// When TEST_P is found without a matching INSTANTIATE_TEST_SUITE_P
// to creates test cases for it, a syntetic test case is
// to creates test cases for it, a synthetic test case is
// inserted to report ether an error or a log message.
//
// This configuration bit will likely be removed at some point.

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(
@ -79,12 +81,38 @@ client_cert_pem = custom_target(
command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '370', '-req', '-CA', '@INPUT1@', '-CAkey', '@INPUT2@', '-CAcreateserial', '-out', '@OUTPUT@']
)
client_encrypted_key_pem = custom_target(
'client_encrypted_key_pem',
output: 'client_encrypted.key.pem',
command: [openssl, 'genrsa', '-aes256', '-passout', 'pass:test012!', '-out', '@OUTPUT@', '2048']
)
client_encrypted_temp_req = custom_target(
'client_encrypted_temp_req',
input: client_encrypted_key_pem,
output: 'client_encrypted_temp_req',
command: [openssl, 'req', '-new', '-batch', '-config', test_conf, '-key', '@INPUT@', '-passin', 'pass:test012!', '-out', '@OUTPUT@']
)
client_encrypted_cert_pem = custom_target(
'client_encrypted_cert_pem',
input: [client_encrypted_temp_req, rootca_cert_pem, rootca_key_pem],
output: 'client_encrypted.cert.pem',
command: [openssl, 'x509', '-in', '@INPUT0@', '-days', '370', '-req', '-CA', '@INPUT1@', '-CAkey', '@INPUT2@', '-CAcreateserial', '-out', '@OUTPUT@']
)
# 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 = []
if gtest_dep.version().version_compare('>=1.13.0')
test_options += 'cpp_std=c++14'
endif
test(
'main',
@ -93,8 +121,10 @@ test(
'test.cc',
dependencies: [
cpp_httplib_dep,
gtest_dep
]
gtest_dep,
libcurl_dep
],
override_options: test_options
),
depends: [
key_pem,
@ -105,7 +135,9 @@ test(
rootca_key_pem,
rootca_cert_pem,
client_key_pem,
client_cert_pem
client_cert_pem,
client_encrypted_key_pem,
client_encrypted_cert_pem
],
workdir: meson.current_build_dir(),
timeout: 300

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,12 +5,11 @@
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);
EXPECT_EQ(407, res->status);
EXPECT_EQ(StatusCode::ProxyAuthenticationRequired_407, res->status);
}
TEST(ProxyTest, NoSSLBasic) {
@ -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");
@ -51,7 +50,7 @@ void RedirectProxyText(T& cli, const char *path, bool basic) {
auto res = cli.Get(path);
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
TEST(RedirectTest, HTTPBinNoSSLBasic) {
@ -100,46 +99,46 @@ 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");
{
auto res = cli.Get("/basic-auth/hello/world");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(401, res->status);
EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
}
{
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(200, res->status);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
{
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(200, res->status);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
{
cli.set_basic_auth("hello", "bad");
auto res = cli.Get("/basic-auth/hello/world");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(401, res->status);
EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
}
{
cli.set_basic_auth("bad", "world");
auto res = cli.Get("/basic-auth/hello/world");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(401, res->status);
EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
}
}
@ -158,15 +157,14 @@ 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");
{
auto res = cli.Get("/digest-auth/auth/hello/world");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(401, res->status);
EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
}
{
@ -181,15 +179,16 @@ 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(200, res->status);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
cli.set_digest_auth("hello", "bad");
for (auto path : paths) {
auto res = cli.Get(path.c_str());
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(401, res->status);
EXPECT_EQ(StatusCode::Unauthorized_401, res->status);
}
// NOTE: Until httpbin.org fixes issue #46, the following test is commented
@ -198,7 +197,7 @@ void DigestAuthTestFromHTTPWatch(T& cli) {
// for (auto path : paths) {
// auto res = cli.Get(path.c_str());
// ASSERT_TRUE(res != nullptr);
// EXPECT_EQ(401, res->status);
// EXPECT_EQ(StatusCode::Unauthorized_401, 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");
@ -234,11 +232,11 @@ void KeepAliveTest(T& cli, bool basic) {
{
auto res = cli.Get("/httpbin/get");
EXPECT_EQ(200, res->status);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
{
auto res = cli.Get("/httpbin/redirect/2");
EXPECT_EQ(200, res->status);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
{
@ -249,10 +247,11 @@ 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(200, res->status);
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n",
res->body);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
}
@ -260,7 +259,7 @@ void KeepAliveTest(T& cli, bool basic) {
int count = 10;
while (count--) {
auto res = cli.Get("/httpbin/get");
EXPECT_EQ(200, res->status);
EXPECT_EQ(StatusCode::OK_200, res->status);
}
}
}

8192
test/www/dir/1MB.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,3 +5,4 @@
configure_file(input: 'index.html', output: 'index.html', copy: true)
configure_file(input: 'test.abcde', output: 'test.abcde', copy: true)
configure_file(input: 'test.html', output: 'test.html', copy: true)
configure_file(input: '1MB.txt', output: '1MB.txt', copy: true)

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 @@
日本語コンテンツ