Compare commits

...

176 Commits

Author SHA1 Message Date
yhirose 66f698fab6 Fixed build errors with some examples 2020-05-16 00:50:52 -04:00
yhirose b9a9df4d73 Fixed problem with writing large data 2020-05-15 22:21:58 -04:00
yhirose 25aa3ca982 Added std::ostream os in DataSink. 2020-05-15 21:26:13 -04:00
yhirose 2d67211183 Added more unit tests for the simple interface 2020-05-14 18:25:18 -04:00
yhirose f4c5d94d74 Updated version in the User Agent string 2020-05-14 18:07:02 -04:00
yhirose 63a96aeb20 Improved Client2 interface 2020-05-14 12:51:34 -04:00
yhirose bbb83d12c1 Removed default parameter values in Client and SSLClient constructors 2020-05-14 08:51:32 -04:00
yhirose 2d4b42b70b Removed url 2020-05-14 01:43:06 -04:00
yhirose 1919d08f71 Added Client2 2020-05-14 01:36:56 -04:00
yhirose 824c02fcd3 Code cleanup 2020-05-14 01:08:36 -04:00
yhirose 2c0613f211 Fix #472 2020-05-13 21:48:14 -04:00
Saika Fatih be45ff1ff1 A detail about Gzip support (#475)
* Typos fixed

* README.md edited.libz should be linked for GZIP support.
2020-05-12 17:38:51 -04:00
Saika Fatih 803ebe1e20 Typos fixed (#474) 2020-05-12 13:18:58 -04:00
yhirose ba685dbe48 Fixed potential infinite loop with content receiver 2020-05-10 20:45:57 -04:00
yhirose 49c4c2f9c1 Fix #459 2020-05-10 20:39:16 -04:00
yhirose 58909f5917 Fix #466 2020-05-10 15:58:53 -04:00
yhirose 5982b5c360 Fix #471 2020-05-10 14:18:03 -04:00
yhirose eb1fe5b191 Fixed warnings 2020-05-09 15:08:49 -04:00
yhirose 5e01587ed6 Fixed problem created in the previous commit 2020-05-09 13:43:06 -04:00
yhirose 5935d9fa59 Commented out the unit test for digest auth. 2020-05-09 13:32:51 -04:00
PixlRainbow 5bb4c12c6b Fix #465 (#467)
update digest header username to use username parameter instead of "hello" test value
2020-05-09 08:29:08 -04:00
yhirose 85637844c9 Updated README 2020-05-07 21:13:45 -04:00
Daniel Ottiger d043b18097 keepalive: support multiple post using content provider (#461) 2020-05-07 08:31:14 -04:00
yhirose 31bb13abd2 Removed TravisCI badge from README 2020-05-04 22:19:17 -04:00
yhirose 8728db7477 Apply IPV6_V6ONLY only when socket is AF_INET6 2020-05-04 22:16:43 -04:00
yhirose 1c50ac3667 Stop using TravisCI anymore due to IPv6 issue 2020-05-04 22:14:03 -04:00
yhirose cf386f97fd Merge branch 'master' of https://github.com/yhirose/cpp-httplib 2020-05-04 22:13:17 -04:00
Daniel Ottiger b2203bb05a server: support dual-stack server socket (#450)
According to RFC 3493 the socket option IPV6_V6ONLY
should be off by default, see
https://tools.ietf.org/html/rfc3493#page-22 (chapter 5.3).

However this does not seem to be the case on all systems.
For instance on any Windows OS, the option is on by default.

Therefore clear this option in order to allow
an server socket which can support IPv6 and IPv4 at the same time.
2020-05-04 22:13:12 -04:00
yhirose f5b806d995 Added a test case for #396. 2020-05-04 21:26:14 -04:00
yhirose 3895210f19 Code format 2020-05-04 21:25:59 -04:00
yhirose d45250fd88 Appled HANDLE_EINTR to send and select system calls 2020-05-01 21:38:23 -04:00
yhirose 528cacdc0d Changed CPPHTTPLIB_THREAD_POOL_COUNT back to 8. (#454) 2020-05-01 21:23:02 -04:00
Matthew DeVore ed1b6afa10 Fix crash caused by header field regex complexity (#457) 2020-05-01 12:44:13 -04:00
yhirose 08fc7085e5 Fixed #456 2020-04-30 19:40:23 -04:00
yhirose 8333340e2c Chagned to use inline function instead of macro 2020-04-27 12:36:39 -04:00
yhirose 98a0887571 Merge branch 'je-ik-sketch-eintr-handling' 2020-04-27 12:33:21 -04:00
Jan Lukavsky b0a189e50e Sketch handling EINTR errors 2020-04-27 17:36:44 +02:00
yhirose 776b3ffbf9 Code format 2020-04-25 18:01:48 -04:00
yhirose a061b97677 Adjust appveyor.yml 2020-04-25 18:01:12 -04:00
yhirose d359e3a5f7 Renave queue_adjust to on_idle (#442) 2020-04-25 17:56:55 -04:00
evg82 5928e0af1a TaskQueue method to internal size adjust (#442)
I use a custom TaskQueue, with variable number of workers, adding workers on demand is an easy task when new connection arrive (in enqueue function) however i need another funtion to be called even (or better) went no new connections arrives to reduce workers count. I only added a new virtual method in TaskQueue class to allow custom class to adjust workers size over time. Even if this methods is called frequenlty custom class can keep a "last_update" counter to check if need to adjust worker count or any other internal task. Without this function i need an external thread to make this adjust task.
2020-04-25 17:55:20 -04:00
yhirose a5005789ff Fixed Visual Studio compiler warnings with x64 platform (Resolve #440 and #446) (#448) 2020-04-25 17:13:14 -04:00
yhirose fae30af47d Updated appveyor.yml 2020-04-25 15:48:19 -04:00
Hoa Thiên Vũ 2feea0c9ab Fixed error: ‘ULONG_MAX’ was not declared in this scope on line 1921 (#445)
* Fixed error:
ULONG_MAX is defined in the limits.h header file. Putting #include <climits>
```
httplib.h: In function ‘bool httplib::detail::read_content_chunked(httplib::Stream&, httplib::ContentReceiver)’:
httplib.h:1921:22: error: ‘ULONG_MAX’ was not declared in this scope
     if (chunk_len == ULONG_MAX) { return false; }
                      ^~~~~~~~~
httplib.h:1921:22: note: suggested alternative: ‘_SC_ULONG_MAX’
     if (chunk_len == ULONG_MAX) { return false; }
                      ^~~~~~~~~
                      _SC_ULONG_MAX
```

* Move #include <climits> to after #include <cassert>
2020-04-24 12:02:19 -04:00
yhirose a2e4af54b7 Fix #399 2020-04-23 23:09:04 -04:00
yhirose d0b123be26 Support remote_addr and remote_port REMOTE_PORT header in client Request (#433) 2020-04-23 22:12:12 -04:00
Matthew DeVore df138366e4 Fail to read a chunk if its length is >= ULONG_MAX (#444)
We cannot trivially support such large chunks, and the maximum value
std::strtoul can parse accurately is ULONG_MAX-1. Error out early if the
length is longer than that.
2020-04-23 10:59:15 -04:00
Matthew DeVore c49441ae64 Do not throw exceptions when parsing request chunks (#441)
detail::read_content_chunked was using std::stoul to parse the
hexadecimal chunk lengths for "Transfer-Encoding: chunked" requests.
This throws an exception if the string does not begin with any valid
digits. read_content_chunked is not called in the context of a try block
so this caused the process to terminate.

Rather than use exceptions, I opted for std::stroul, which is similar to
std::stoul but does not throw exceptions. Since malformed user input is
not particularly exceptional, and some projects are compiled without
exception support, this approach seems both more portable and more
correct.
2020-04-23 09:05:45 -04:00
yhirose e1506fa186 Code cleanup 2020-04-22 21:43:16 -04:00
yhirose ad9fd3bd93 Fix #436 2020-04-22 21:42:58 -04:00
yhirose 05e0253195 Fixed test error 2020-04-21 23:07:51 -04:00
yhirose da26b517a3 Added url::Get interface 2020-04-21 23:00:39 -04:00
yhirose 2b7a968468 Added a unit test for URL interface 2020-04-21 21:21:31 -04:00
yhirose 240cc85ccb Fixed regex problem for recirect location 2020-04-21 21:18:29 -04:00
yhirose 129e2f00b8 Removed unnecessary noexcept 2020-04-20 19:42:05 -04:00
Daniel Ottiger da746c6e67 SSLClient::set_ca_cert_store: mark as inline (#435) 2020-04-20 12:53:39 -04:00
yhirose 3451da940d Code format 2020-04-19 22:05:04 -04:00
yhirose 38a6b3e69f Fixed warning 2020-04-19 22:04:29 -04:00
yhirose d1037ee9fd Close #433 2020-04-18 16:38:15 -04:00
Daniel Ottiger 2ece5f116b Pass certs and keys from memory (#432)
* SSLServer: add constructor to pass ssl-certificates and key from memory

* SSLClient: add constructor to pass ssl-certificates and key from memory

* add TestCase for passing certificates from memory to SSLClient/SSLServer
2020-04-18 16:26:06 -04:00
yhirose c2b6e4ac04 Fix #431 2020-04-17 21:48:16 -04:00
yhirose 8674555b88 Removed CMakeLists.txt. (Fix #421) 2020-04-13 20:56:21 -04:00
yhirose 85327e19ae Fix #425 2020-04-12 15:33:08 -04:00
Alexandre Taillefer ed8efea98b Added support for DELETE request body (#418)
* Added support for DELETE request body

* Fixed DELETE request body test case typo

Co-authored-by: Alexandre Taillefer <alexandre.taillefer@pwc.ca>
2020-04-07 15:51:52 -04:00
Max 1ccddd1b0b SSL_shutdown() only if not already closed by remote (#413) 2020-04-06 10:30:21 -04:00
yhirose 992f3dc690 Code cleanup 2020-04-03 09:33:29 -04:00
yhirose 402d47e2cd Fix #407 2020-03-31 19:42:53 -04:00
yhirose 171fc2e353 Fix #403. Added more status codes based on MDN document 2020-03-26 20:50:40 -04:00
SoenkeHeeren ced4160d05 add http status code 201 to show the right status message in return headers (#402) 2020-03-26 12:20:32 -04:00
yhirose 5b51aa6851 Revert "Add 1000-concurrency-result report"
This reverts commit b0af78e340.
2020-03-24 17:30:32 -04:00
Igor [hyperxor] dc13cde820 Minor improvements in httplib classes (#395) 2020-03-23 06:54:13 -04:00
yhirose b0af78e340 Add 1000-concurrency-result report 2020-03-21 15:49:26 +00:00
Andrew Gasparovic 914c8860e8 Accept content by value to allow moving
Previously, calling set_content always resulted in 's' being copied. With this change, there will still be the same number of copies made (1) when doing `set_content(my_value, ...)`, but there will be no copies if a caller elects to do `set_content(std::move(value), ...)` or `set_content(some_function_that_returns_a_temporary(), ...)` instead.
2020-03-21 00:39:07 -04:00
yhirose dc6a72a0fd Fix #387 2020-03-17 18:03:52 -04:00
yhirose 685533ba50 Fixed warnings on Windows due to max/min macro 2020-03-16 13:58:09 -04:00
yhirose 6e46ccb37c Updated README 2020-03-15 12:05:12 -04:00
Aristo Chen ac18b70a0f Update calculation formula for progress percentage (#386) 2020-03-15 08:29:27 -04:00
yhirose e1acb949e7 Fix #382 2020-03-13 18:43:29 -04:00
yhirose ab96f49766 Fixed problem that line end char is missing on start messagein simple
server example
2020-03-13 16:36:33 -04:00
Oleg Vorobiov 7b3cea5317 Prevent an implicit capture of 'this' via '[=]' (#381) 2020-03-12 12:31:22 -04:00
yhirose 26deffe0c6 Not to send 'EXCEPTION_WHAT' header to client 2020-03-10 17:44:36 -04:00
Rafael Leira e07c5fec01 simplest way to catch handler exceptions 2020-03-10 17:44:36 -04:00
miketsts 6e473a7c5c Fix conversion to ‘int’ from ‘long int’ warning (#377)
Co-authored-by: Michael Tseitlin <michael.tseitlin@concertio.com>
2020-03-10 14:48:14 -04:00
yhirose c74129a1c2 Fix #372 (#374) 2020-03-09 23:59:00 -04:00
yhirose 18e750b4e7 Code cleanup 2020-03-09 19:47:28 -04:00
Matthew DeVore bf7700d192 Fix exception that occurs with libc++ regex engine (#368)
The regex that parses header lines potentially causes an unlimited
amount of backtracking, which can cause an exception in the libc++ regex
engine.

The exception that occurs looks like this and is identical to the
message of the exception fixed in
https://github.com/yhirose/cpp-httplib/pull/280:

	libc++abi.dylib: terminating with uncaught exception of type
	std::__1::regex_error: The complexity of an attempted match
	against a regular expression exceeded a pre-set level.

This commit eliminates the problematic backtracking.
2020-02-28 06:31:39 -05:00
yhirose 3da925d6fe Adjusted a unit test. 2020-02-25 08:29:29 -05:00
yhirose 319417f26d Updated README 2020-02-24 21:50:07 -05:00
yhirose 4c3b119dde Code format 2020-02-24 21:17:02 -05:00
yhirose 6de8684328 Merge branch 'hyperxor-remove_code_duplication_in_getting_query' 2020-02-24 21:15:01 -05:00
hyperxor ccc9a9b3f4 Remove code duplication in converting params to query 2020-02-25 02:30:34 +03:00
rymis f2bb9c45d6 Support for deflate compression (#360) 2020-02-24 11:48:00 -05:00
yhirose 9a663aa94e Added a unit test. 2020-02-21 11:48:47 -05:00
yhirose d0d744d520 Fixed compiler warning with Visual C++. Close #358 2020-02-20 17:30:04 -05:00
yhirose fce8e6fefd Merge pull request #356 from samhocevar/fix-shadow-declarations
Fix a few shadowed variable compilation warnings.
2020-02-17 09:01:47 -05:00
Sam Hocevar 180aa32ebf Fix a few shadowed variable compilation warnings. 2020-02-17 06:58:30 +01:00
yhirose fe01fa760b Update README 2020-02-14 22:07:39 -05:00
yhirose d61d63dd97 Added unit tests for SSLServer::bind_to_any_port 2020-02-14 21:59:37 -05:00
yhirose 3fe13ecc91 Updated README 2020-02-14 21:49:09 -05:00
yhirose 064cc6810e Fix #352 2020-02-13 17:40:06 -05:00
yhirose 464cc89b77 Fix #351 2020-02-12 22:35:52 -05:00
yhirose ca5a50d2c9 Fix #349 2020-02-11 00:26:15 -05:00
yhirose b251668522 Fixed build problem. 2020-02-03 22:45:50 -05:00
yhirose 9ee740fe8f Updated README 2020-02-02 20:57:29 -05:00
yhirose 851edaf77f Code format 2020-02-02 20:02:16 -05:00
yhirose 1a2a6e2b01 Updated README 2020-02-01 09:24:42 -05:00
yhirose ac7742bb32 Changed the order of parameters of set_mounting_point. 2020-02-01 09:18:24 -05:00
yhirose 82c11168c1 Merge pull request #342 from yhirose/remove_mount_point
Fix #341
2020-01-31 20:41:39 -05:00
yhirose 7c5197c86c Updated README 2020-01-31 20:40:33 -05:00
yhirose 8801e51138 Fix #341 2020-01-31 20:35:20 -05:00
yhirose 89740a808d Added a contributor to README 2020-01-28 06:34:10 -05:00
yhirose 2377a20e0b Merge pull request #340 from vitalyster/head_static
HEAD support for static file server
2020-01-28 06:32:32 -05:00
Vitaly Takmazov 5e43680486 HEAD support for static file server 2020-01-28 12:00:27 +03:00
yhirose 79df842cc5 Updated README 2020-01-26 18:34:50 -05:00
yhirose 48a4a5812e Merge pull request #338 from TheMaverickProgrammer/master
fixed missing import
2020-01-25 20:44:59 -05:00
TheMaverickProgrammer a7a6df49a4 Update split.py 2020-01-25 17:19:15 -06:00
TheMaverickProgrammer e932c7e1ec Update split.py
now works with legacy Python ( < 3.0)
2020-01-25 17:17:34 -06:00
yhirose f94c3f1dc9 Updated README 2020-01-21 23:45:21 -05:00
yhirose 4d545cb932 Fix #335 2020-01-21 09:09:05 -05:00
yhirose f5e19faae7 Updated README 2020-01-17 23:21:42 -05:00
yhirose 2e360f9dd6 Improved Stream interface 2020-01-16 23:28:11 -05:00
yhirose e5ca863de5 Merge pull request #334 from vvanelslande/add_503
Add status message: 503 Service Unavailable
2020-01-16 06:59:31 -05:00
Valentin Vanelslande 126f1d177e Add status message: 503 Service Unavailable 2020-01-16 00:59:24 -05:00
yhirose b557ac9328 Code format 2020-01-14 17:04:51 -05:00
yhirose f6db19959f Merge pull request #333 from stupedama/master
std::thread::hardware_concurrency
2020-01-14 17:04:17 -05:00
yhirose 6b4df41b30 Fix #330 2020-01-14 17:02:25 -05:00
yhirose 0d81e20129 Fix #332 2020-01-14 14:59:20 -05:00
Fredrik Fjeldvær 26cb83ed6c if std::thread::hardware_concurrency() is 0 use 2 threads. also -1 thread because we already have one thread from the main function 2020-01-14 17:48:51 +01:00
yhirose b4f808da74 Updated example/upload.cc 2020-01-10 18:38:38 -05:00
yhirose 7fbb8bb3fd Merge pull request #326 from vvanelslande/add_202
Add status message for 202 Accepted
2020-01-10 18:37:38 -05:00
Valentin Vanelslande db27812198 Add status message for 202 Accepted 2020-01-10 17:50:37 -05:00
yhirose 6fe6fd5dbe Fixed build errors 2020-01-10 09:40:26 -05:00
yhirose 0ee9660f3d Code format 2020-01-10 09:35:07 -05:00
yhirose a15d16a9de Moved Stream concrete classes into detail namespace 2020-01-10 09:33:14 -05:00
yhirose dfebfd9033 Merge pull request #325 from rockwotj/master
Properly implement BufferStream::read
2020-01-10 07:54:15 -05:00
Tyler Rockwood fcdaa24fc5 Properly implement BufferStream::read
The existing implementation did not advance the buffer at all.
2020-01-09 22:05:59 -06:00
yhirose 7f749740f7 Merge pull request #324 from hyperxor/use_cpp_11_for_delays
Use sleep_for and chrono for delays in tests
2020-01-09 17:08:44 -05:00
hyperxor 7b4494748e fix indentation 2020-01-10 00:17:40 +03:00
hyperxor 7e1c107029 Use sleep_for and chrono for delays in tests 2020-01-10 00:15:18 +03:00
yhirose db7ae0ec21 Merge pull request #322 from hyperxor/fix_response_move
Fix suppressed Response class objects moving
2020-01-08 22:09:17 -05:00
hyperxor b16905ec8b Fix Response move 2020-01-08 23:13:04 +03:00
yhirose 2f72845008 Fix #319 2020-01-07 23:40:11 -05:00
yhirose 68aeb4a06a Merge pull request #317 from hyperxor/tiny_improvement_in_data_sink
Tiny improvement in DataSink class
2020-01-07 07:03:38 -05:00
hyperxor 568fda62b4 Tiny improvement in DataSink class 2020-01-07 13:25:04 +03:00
yhirose 04957c0f08 Fix #315 2020-01-06 17:13:31 -05:00
yhirose 96e9ec0663 Improved DataSink interface 2020-01-05 23:59:54 -05:00
yhirose c58fca5dba Added more tests 2020-01-03 07:57:40 -05:00
yhirose d2fae4031c Fixed build errors 2020-01-03 01:36:59 -05:00
yhirose de844e67ef Proxy support for Keep-Alive requests 2020-01-03 01:24:07 -05:00
yhirose 6c0e021554 Fixed socket leak 2020-01-02 17:01:02 -05:00
yhirose e8d33a77e0 Updated README 2020-01-02 13:08:40 -05:00
yhirose aa630e3062 Fix #311 2020-01-02 13:02:05 -05:00
yhirose 301a419c02 Updated README 2019-12-26 19:50:51 -05:00
yhirose fcbcbd53bd Fix #306 2019-12-26 18:48:22 -05:00
yhirose 1bf616d653 Fix #303 2019-12-26 17:50:53 -05:00
yhirose ba7c7dc4a3 Added linux to .travis.yaml 2019-12-24 22:46:32 -05:00
yhirose aa543240db Added test for post request with query string and body 2019-12-24 21:55:29 -05:00
yhirose 5675cad407 Added proxy test in Makefile 2019-12-22 21:07:26 -05:00
yhirose 079d3605ea Changed to use docker-compose for squid 2019-12-22 19:11:02 -05:00
yhirose 2c6da365d9 Merge pull request #300 from vvanelslande/accpet
Change Accpet-Encoding to Accept-Encoding
2019-12-22 15:39:47 -05:00
yhirose 38adeaf02c Fixed problem with proxy support and added unit tests 2019-12-22 15:37:01 -05:00
Valentin Vanelslande b3814b2b80 Change Accpet-Encoding to Accept-Encoding 2019-12-22 13:02:20 -05:00
yhirose a444b612af V0.5.0 2019-12-22 12:52:08 -05:00
yhirose ed6d949f42 Fix #299 2019-12-22 12:50:25 -05:00
yhirose d28cd3f937 Code cleanup 2019-12-21 23:20:30 -05:00
yhirose 8cc3e6c434 Merge pull request #296 from yhirose/connect
CONNECT method support on client
2019-12-21 23:09:10 -05:00
yhirose 26fbc1b7c0 Merge pull request #297 from hyperxor/fix_progress_redundant_copying
Fix redundant Progress copy in Get methods
2019-12-21 07:43:45 -05:00
hyperxor 0dc653f45a Fix redundant Progress copy in Get methods 2019-12-21 10:57:06 +03:00
yhirose 7a58c0a430 Updated README regarding regex issue in g++ 4.8 and below 2019-12-20 23:16:05 -05:00
yhirose dabaa51a7d Updated README 2019-12-20 23:12:24 -05:00
yhirose a1cfc0f377 Fixed problem with redirect 2019-12-20 13:25:11 -05:00
yhirose eb4fcb5003 CONNECT method support on client 2019-12-20 06:59:59 -05:00
yhirose ae43c96984 Merge pull request #295 from yhirose/timeout
Fix #294
2019-12-18 17:57:23 -05:00
yhirose 9c81693801 Fix #294 2019-12-18 17:47:36 -05:00
yhirose 80202c9f62 Merge pull request #292 from Bendr0id/fix_socket_create_on_older_windows_systems
Adds workaround for socket creation on older Windows variants
2019-12-18 07:09:48 -05:00
Ben Gräf 094a6a614a Adds workaround for socket creation on older Windows variants
Since the WSA_FLAG_NO_HANDLE_INHERIT is only supported on Windows 7 SP1 and above the socket creation fails on older Windows Systems.
     
Let's try to create a socket the old way in this case.
     
Reference:
https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketa
     
WSA_FLAG_NO_HANDLE_INHERIT:
This flag is supported on Windows 7 with SP1, Windows Server 2008 R2 with SP1, and later
2019-12-18 07:49:36 +01:00
28 changed files with 3660 additions and 1036 deletions
+3
View File
@@ -3,12 +3,15 @@ tags
example/server
example/client
example/hello
example/simplecli
example/simplesvr
example/benchmark
example/redirect
example/sse
example/upload
example/*.pem
test/test
test/test_proxy
test/test.xcodeproj/xcuser*
test/test.xcodeproj/*/xcuser*
test/*.pem
-13
View File
@@ -1,13 +0,0 @@
# Environment
language: cpp
os:
- osx
# Compiler selection
compiler:
- clang
# Build/test steps
script:
- cd ${TRAVIS_BUILD_DIR}/test
- make all
-29
View File
@@ -1,29 +0,0 @@
cmake_minimum_required(VERSION 3.7.0)
project(httplib)
set(CMAKE_CXX_STANDARD 11)
# Include
include(GNUInstallDirs)
include(ExternalProject)
add_library(${PROJECT_NAME} INTERFACE)
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_11)
target_include_directories(${PROJECT_NAME} INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
install(TARGETS ${PROJECT_NAME} EXPORT httplibConfig
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES httplib.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})
install(EXPORT httplibConfig DESTINATION share/httplib/cmake)
export(TARGETS ${PROJECT_NAME} FILE httplibConfig.cmake)
#add_subdirectory(example)
#add_subdirectory(test)
+244 -115
View File
@@ -2,13 +2,14 @@ cpp-httplib
===========
[![](https://github.com/yhirose/cpp-httplib/workflows/test/badge.svg)](https://github.com/yhirose/cpp-httplib/actions)
[![Build Status](https://travis-ci.org/yhirose/cpp-httplib.svg?branch=master)](https://travis-ci.org/yhirose/cpp-httplib)
[![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-httplib?branch=master&svg=true)](https://ci.appveyor.com/project/yhirose/cpp-httplib)
A C++ single-file header-only cross platform HTTP/HTTPS library.
A C++11 single-file header-only cross platform HTTP/HTTPS library.
It's extremely easy to setup. Just include **httplib.h** file in your code!
For Windows users: Please read [this note](https://github.com/yhirose/cpp-httplib#windows).
Server Example
--------------
@@ -17,24 +18,34 @@ Server Example
int main(void)
{
using namespace httplib;
using namespace httplib;
Server svr;
Server svr;
svr.Get("/hi", [](const Request& req, Response& res) {
res.set_content("Hello World!", "text/plain");
});
svr.Get("/hi", [](const Request& req, Response& res) {
res.set_content("Hello World!", "text/plain");
});
svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
auto numbers = req.matches[1];
res.set_content(numbers, "text/plain");
});
svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
auto numbers = req.matches[1];
res.set_content(numbers, "text/plain");
});
svr.Get("/stop", [&](const Request& req, Response& res) {
svr.stop();
});
svr.Get("/body-header-param", [](const Request& req, Response& res) {
if (req.has_header("Content-Length")) {
auto val = req.get_header_value("Content-Length");
}
if (req.has_param("key")) {
auto val = req.get_param_value("key");
}
res.set_content(req.body, "text/plain");
});
svr.listen("localhost", 1234);
svr.Get("/stop", [&](const Request& req, Response& res) {
svr.stop();
});
svr.listen("localhost", 1234);
}
```
@@ -50,34 +61,70 @@ svr.listen_after_bind();
### Static File Server
```cpp
svr.set_base_dir("./www"); // This is same as `svr.set_base_dir("./www", "/")`;
// Mount / to ./www directory
auto ret = svr.set_mount_point("/", "./www");
if (!ret) {
// The specified base directory doesn't exist...
}
// Mount /public to ./www directory
ret = svr.set_mount_point("/public", "./www");
// Mount /public to ./www1 and ./www2 directories
ret = svr.set_mount_point("/public", "./www1"); // 1st order to search
ret = svr.set_mount_point("/public", "./www2"); // 2nd order to search
// Remove mount /
ret = svr.remove_mount_point("/");
// Remove mount /public
ret = svr.remove_mount_point("/public");
```
```cpp
svr.set_base_dir("./www", "/public");
// User defined file extension and MIME type mappings
svr.set_file_extension_and_mimetype_mapping("cc", "text/x-c");
svr.set_file_extension_and_mimetype_mapping("cpp", "text/x-c");
svr.set_file_extension_and_mimetype_mapping("hh", "text/x-h");
```
```cpp
svr.set_base_dir("./www1", "/public"); // 1st order
svr.set_base_dir("./www2", "/public"); // 2nd order
```
The followings are built-in mappings:
| Extension | MIME Type |
| :-------- | :--------------------- |
| txt | text/plain |
| html, htm | text/html |
| css | text/css |
| jpeg, jpg | image/jpg |
| png | image/png |
| gif | image/gif |
| svg | image/svg+xml |
| ico | image/x-icon |
| json | application/json |
| pdf | application/pdf |
| js | application/javascript |
| wasm | application/wasm |
| xml | application/xml |
| xhtml | application/xhtml+xml |
NOTE: These the static file server methods are not thread safe.
### Logging
```cpp
svr.set_logger([](const auto& req, const auto& res) {
your_logger(req, res);
your_logger(req, res);
});
```
### Error Handler
### Error handler
```cpp
svr.set_error_handler([](const auto& req, auto& res) {
const char* fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
char buf[BUFSIZ];
snprintf(buf, sizeof(buf), fmt, res.status);
res.set_content(buf, "text/html");
auto fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
char buf[BUFSIZ];
snprintf(buf, sizeof(buf), fmt, res.status);
res.set_content(buf, "text/html");
});
```
@@ -85,31 +132,12 @@ svr.set_error_handler([](const auto& req, auto& res) {
```cpp
svr.Post("/multipart", [&](const auto& req, auto& res) {
auto size = req.files.size();
auto ret = req.has_file("name1");
const auto& file = req.get_file_value("name1");
// file.filename;
// file.content_type;
// file.content;
});
```
### Send content with Content provider
```cpp
const uint64_t DATA_CHUNK_SIZE = 4;
svr.Get("/stream", [&](const Request &req, Response &res) {
auto data = new std::string("abcdefg");
res.set_content_provider(
data->size(), // Content length
[data](uint64_t offset, uint64_t length, DataSink sink) {
const auto &d = *data;
sink(&d[offset], std::min(length, DATA_CHUNK_SIZE));
},
[data] { delete data; });
auto size = req.files.size();
auto ret = req.has_file("name1");
const auto& file = req.get_file_value("name1");
// file.filename;
// file.content_type;
// file.content;
});
```
@@ -140,34 +168,51 @@ svr.Post("/content_receiver",
});
```
### Send content with Content provider
```cpp
const size_t DATA_CHUNK_SIZE = 4;
svr.Get("/stream", [&](const Request &req, Response &res) {
auto data = new std::string("abcdefg");
res.set_content_provider(
data->size(), // Content length
[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.
},
[data] { delete data; });
});
```
### Chunked transfer encoding
```cpp
svr.Get("/chunked", [&](const Request& req, Response& res) {
res.set_chunked_content_provider(
[](uint64_t offset, DataSink sink, Done done) {
sink("123", 3);
sink("345", 3);
sink("789", 3);
done();
[](size_t offset, DataSink &sink) {
sink.write("123", 3);
sink.write("345", 3);
sink.write("789", 3);
sink.done();
return true; // return 'false' if you want to cancel the process.
}
);
});
```
### Server-Sent Events
Please check [here](https://github.com/yhirose/cpp-httplib/blob/master/example/sse.cc).
### Default thread pool support
Set thread count to 8:
```cpp
#define CPPHTTPLIB_THREAD_POOL_COUNT 8
```
`ThreadPool` is used as a default task queue, and the default thread count is set to value from `std::thread::hardware_concurrency()`.
Disable the default thread pool:
```cpp
#define CPPHTTPLIB_THREAD_POOL_COUNT 0
```
You can change the thread count by setting `CPPHTTPLIB_THREAD_POOL_COUNT`.
### Override the default thread pool with yours
@@ -195,47 +240,64 @@ svr.new_task_queue = [] {
};
```
### 'Expect: 100-continue' handler
As default, the server sends `100 Continue` response for `Expect: 100-continue` header.
```cpp
// Send a '417 Expectation Failed' response.
svr.set_expect_100_continue_handler([](const Request &req, Response &res) {
return 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;
});
```
Client Example
--------------
### GET
```c++
#include <httplib.h>
#include <iostream>
int main(void)
{
httplib::Client cli("localhost", 1234);
// IMPORTANT: 1st parameter must be a hostname or an IP adress string.
httplib::Client cli("localhost", 1234);
auto res = cli.Get("/hi");
if (res && res->status == 200) {
std::cout << res->body << std::endl;
}
auto res = cli.Get("/hi");
if (res && res->status == 200) {
std::cout << res->body << std::endl;
}
}
```
### GET with HTTP headers
```c++
httplib::Headers headers = {
{ "Accept-Encoding", "gzip, deflate" }
};
auto res = cli.Get("/hi", headers);
httplib::Headers headers = {
{ "Accept-Encoding", "gzip, deflate" }
};
auto res = cli.Get("/hi", headers);
```
### GET with Content Receiver
```c++
std::string body;
std::string body;
auto res = cli.Get("/large-data",
[&](const char *data, uint64_t data_length) {
body.append(data, data_length);
return true;
});
auto res = cli.Get("/large-data",
[&](const char *data, size_t data_length) {
body.append(data, data_length);
return true;
});
assert(res->body.empty());
assert(res->body.empty());
```
### POST
@@ -268,15 +330,15 @@ auto res = cli.Post("/post", params);
### POST with Multipart Form Data
```c++
httplib::MultipartFormDataItems items = {
{ "text1", "text default", "", "" },
{ "text2", "aωb", "", "" },
{ "file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain" },
{ "file2", "{\n \"world\", true\n}\n", "world.json", "application/json" },
{ "file3", "", "", "application/octet-stream" },
};
httplib::MultipartFormDataItems items = {
{ "text1", "text default", "", "" },
{ "text2", "aωb", "", "" },
{ "file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain" },
{ "file2", "{\n \"world\", true\n}\n", "world.json", "application/json" },
{ "file3", "", "", "application/octet-stream" },
};
auto res = cli.Post("/multipart", items);
auto res = cli.Post("/multipart", items);
```
### PUT
@@ -301,8 +363,37 @@ res = cli.Options("/resource/foo");
### Connection Timeout
```c++
httplib::Client cli("localhost", 8080, 5); // timeouts in 5 seconds
cli.set_timeout_sec(5); // timeouts in 5 seconds
```
### Receive content with Content receiver
```cpp
std::string body;
auto res = cli.Get(
"/stream", Headers(),
[&](const Response &response) {
EXPECT_EQ(200, response.status);
return true; // return 'false' if you want to cancel the request.
},
[&](const char *data, size_t data_length) {
body.append(data, data_length);
return true; // return 'false' if you want to cancel the request.
});
```
### Send content with Content provider
```cpp
std::string body = ...;
auto res = cli_.Post(
"/stream", body.size(),
[](size_t offset, size_t length, DataSink &sink) {
sink.write(body.data() + offset, length);
return true; // return 'false' if you want to cancel the request.
},
"text/plain");
```
### With Progress Callback
```cpp
@@ -310,38 +401,43 @@ httplib::Client client(url, port);
// prints: 0 / 000 bytes => 50% complete
std::shared_ptr<httplib::Response> res =
cli.Get("/", [](uint64_t len, uint64_t total) {
printf("%lld / %lld bytes => %d%% complete\n",
len, total,
(int)((len/total)*100));
return true; // return 'false' if you want to cancel the request.
}
cli.Get("/", [](uint64_t len, uint64_t total) {
printf("%lld / %lld bytes => %d%% complete\n",
len, total,
(int)(len*100/total));
return true; // return 'false' if you want to cancel the request.
}
);
```
![progress](https://user-images.githubusercontent.com/236374/33138910-495c4ecc-cf86-11e7-8693-2fc6d09615c4.gif)
This feature was contributed by [underscorediscovery](https://github.com/yhirose/cpp-httplib/pull/23).
### Authentication
NOTE: OpenSSL is required for Digest Authentication, since cpp-httplib uses message digest functions in OpenSSL.
```cpp
// Basic Authentication
cli.set_basic_auth("user", "pass");
// Digest Authentication
cli.set_digest_auth("user", "pass");
```
NOTE: OpenSSL is required for Digest Authentication.
### Proxy server support
```cpp
httplib::Client cli("httplib.org");
cli.set_auth("user", "pass");
cli.set_proxy("host", port);
// Basic
auto res = cli.Get("/basic-auth/user/pass");
// res->status should be 200
// res->body should be "{\n \"authenticated\": true, \n \"user\": \"user\"\n}\n".
// Basic Authentication
cli.set_proxy_basic_auth("user", "pass");
// Digest
res = cli.Get("/digest-auth/auth/user/pass/SHA-256");
// res->status should be 200
// res->body should be "{\n \"authenticated\": true, \n \"user\": \"user\"\n}\n".
// Digest Authentication
cli.set_proxy_digest_auth("user", "pass");
```
NOTE: OpenSSL is required for Digest Authentication.
### Range
```cpp
@@ -371,6 +467,15 @@ Get(requests, "/get-request2");
Post(requests, "/post-request1", "text", "text/plain");
Post(requests, "/post-request2", "text", "text/plain");
const size_t DATA_CHUNK_SIZE = 4;
std::string data("abcdefg");
Post(requests, "/post-request-with-content-provider",
data.size(),
[&](size_t offset, size_t length, DataSink &sink){
sink.write(&data[offset], std::min(length, DATA_CHUNK_SIZE));
},
"text/plain");
std::vector<Response> responses;
if (cli.send(requests, responses)) {
for (const auto& res: responses) {
@@ -420,7 +525,7 @@ cli.enable_server_certificate_verification(true);
Zlib Support
------------
'gzip' compression is available with `CPPHTTPLIB_ZLIB_SUPPORT`.
'gzip' compression is available with `CPPHTTPLIB_ZLIB_SUPPORT`. `libz` should be linked.
The server applies gzip compression to the following MIME type contents:
@@ -450,9 +555,33 @@ httplib.h httplib.cc
NOTE
----
g++ 4.8 cannot build this library since `<regex>` in g++4.8 is [broken](https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions).
### g++
g++ 4.8 and below cannot build this library since `<regex>` in the versions are [broken](https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions).
### Windows
Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32_LEAN_AND_MEAN` beforehand.
```cpp
#include <httplib.h>
#include <Windows.h>
```
```cpp
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <httplib.h>
```
Note: Cygwin on Windows is not supported.
License
-------
MIT license (© 2019 Yuji Hirose)
MIT license (© 2020 Yuji Hirose)
Special Thanks To
-----------------
[These folks](https://github.com/yhirose/cpp-httplib/graphs/contributors) made great contributions to polish this library to totally another level from a simple toy!
+12 -7
View File
@@ -1,9 +1,14 @@
version: 1.0.{build}
image: Visual Studio 2017
build_script:
- cmd: >-
cd test
image:
- Visual Studio 2019
platform:
- x64
build_script:
- cmd: >-
cd test
msbuild.exe test.sln /verbosity:minimal /t:Build /p:Configuration=Release;Platform=%PLATFORM%
msbuild.exe test.sln /verbosity:minimal /t:Build /p:Configuration=Debug;Platform=Win32
test_script:
- cmd: Debug\test.exe
- cmd: x64\Release\test.exe
+8 -2
View File
@@ -5,7 +5,7 @@ OPENSSL_DIR = /usr/local/opt/openssl
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
all: server client hello simplesvr upload redirect benchmark
all: server client hello simplecli simplesvr upload redirect sse benchmark
server : server.cc ../httplib.h Makefile
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
@@ -16,6 +16,9 @@ client : client.cc ../httplib.h Makefile
hello : hello.cc ../httplib.h Makefile
$(CXX) -o hello $(CXXFLAGS) hello.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
simplecli : simplecli.cc ../httplib.h Makefile
$(CXX) -o simplecli $(CXXFLAGS) simplecli.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
simplesvr : simplesvr.cc ../httplib.h Makefile
$(CXX) -o simplesvr $(CXXFLAGS) simplesvr.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
@@ -25,6 +28,9 @@ upload : upload.cc ../httplib.h Makefile
redirect : redirect.cc ../httplib.h Makefile
$(CXX) -o redirect $(CXXFLAGS) redirect.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
sse : sse.cc ../httplib.h Makefile
$(CXX) -o sse $(CXXFLAGS) sse.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
benchmark : benchmark.cc ../httplib.h Makefile
$(CXX) -o benchmark $(CXXFLAGS) benchmark.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
@@ -33,4 +39,4 @@ pem:
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
clean:
rm server client hello simplesvr upload redirect benchmark *.pem
rm server client hello simplecli simplesvr upload redirect sse benchmark *.pem
+1 -1
View File
@@ -15,5 +15,5 @@ int main(void) {
res.set_content("Hello World!", "text/plain");
});
svr.listen("localhost", 1234);
svr.listen("localhost", 8080);
}
+32
View File
@@ -0,0 +1,32 @@
//
// simplecli.cc
//
// Copyright (c) 2019 Yuji Hirose. All rights reserved.
// MIT License
//
#include <httplib.h>
#include <iostream>
#define CA_CERT_FILE "./ca-bundle.crt"
using namespace std;
int main(void) {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto res = httplib::Client2("https://localhost:8080")
.set_ca_cert_path(CA_CERT_FILE)
// .enable_server_certificate_verification(true)
.Get("/hi");
#else
auto res = httplib::Client2("http://localhost:8080").Get("/hi");
#endif
if (res) {
cout << res->status << endl;
cout << res->get_header_value("Content-Type") << endl;
cout << res->body << endl;
}
return 0;
}
+5 -2
View File
@@ -122,9 +122,12 @@ int main(int argc, const char **argv) {
auto base_dir = "./";
if (argc > 2) { base_dir = argv[2]; }
svr.set_base_dir(base_dir);
if (!svr.set_mount_point("/", base_dir)) {
cout << "The specified base directory doesn't exist...";
return 1;
}
cout << "The server started at port " << port << "...";
cout << "The server started at port " << port << "..." << endl;
svr.listen("localhost", port);
+111
View File
@@ -0,0 +1,111 @@
//
// sse.cc
//
// Copyright (c) 2020 Yuji Hirose. All rights reserved.
// MIT License
//
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <httplib.h>
#include <iostream>
#include <mutex>
#include <sstream>
#include <thread>
using namespace httplib;
using namespace std;
class EventDispatcher {
public:
EventDispatcher() {
id_ = 0;
cid_ = -1;
}
void wait_event(DataSink *sink) {
unique_lock<mutex> lk(m_);
int id = id_;
cv_.wait(lk, [&] { return cid_ == id; });
if (sink->is_writable()) { sink->write(message_.data(), message_.size()); }
}
void send_event(const string &message) {
lock_guard<mutex> lk(m_);
cid_ = id_++;
message_ = message;
cv_.notify_all();
}
private:
mutex m_;
condition_variable cv_;
atomic_int id_;
atomic_int cid_;
string message_;
};
const auto html = R"(
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SSE demo</title>
</head>
<body>
<script>
const ev1 = new EventSource("event1");
ev1.onmessage = function(e) {
console.log('ev1', e.data);
}
const ev2 = new EventSource("event2");
ev2.onmessage = function(e) {
console.log('ev2', e.data);
}
</script>
</body>
</html>
)";
int main(void) {
EventDispatcher ed;
Server svr;
svr.Get("/", [&](const Request & /*req*/, Response &res) {
res.set_content(html, "text/html");
});
svr.Get("/event1", [&](const Request & /*req*/, Response &res) {
cout << "connected to event1..." << endl;
res.set_header("Content-Type", "text/event-stream");
res.set_chunked_content_provider([&](size_t /*offset*/, DataSink &sink) {
ed.wait_event(&sink);
return true;
});
});
svr.Get("/event2", [&](const Request & /*req*/, Response &res) {
cout << "connected to event2..." << endl;
res.set_header("Content-Type", "text/event-stream");
res.set_chunked_content_provider([&](size_t /*offset*/, DataSink &sink) {
ed.wait_event(&sink);
return true;
});
});
thread t([&] {
int id = 0;
while (true) {
this_thread::sleep_for(chrono::seconds(1));
cout << "send event: " << id << std::endl;
std::stringstream ss;
ss << "data: " << id << "\n\n";
ed.send_event(ss.str());
id++;
}
});
svr.listen("localhost", 1234);
}
+17 -6
View File
@@ -13,7 +13,8 @@ using namespace std;
const char *html = R"(
<form id="formElem">
<input type="file" name="file" accept="image/*">
<input type="file" name="image_file" accept="image/*">
<input type="file" name="text_file" accept="text/*">
<input type="submit">
</form>
<script>
@@ -36,12 +37,22 @@ int main(void) {
});
svr.Post("/post", [](const Request &req, Response &res) {
auto file = req.get_file_value("file");
cout << "file length: " << file.content.length() << ":" << file.filename
<< endl;
auto image_file = req.get_file_value("image_file");
auto text_file = req.get_file_value("text_file");
ofstream ofs(file.filename, ios::binary);
ofs << file.content;
cout << "image file length: " << image_file.content.length() << endl
<< "image file name: " << image_file.filename << endl
<< "text file length: " << text_file.content.length() << endl
<< "text file name: " << text_file.filename << endl;
{
ofstream ofs(image_file.filename, ios::binary);
ofs << image_file.content;
}
{
ofstream ofs(text_file.filename);
ofs << text_file.content;
}
res.set_content("done", "text/plain");
});
+1784 -730
View File
File diff suppressed because it is too large Load Diff
+9 -1
View File
@@ -1,11 +1,19 @@
import os
import sys
border = '// ----------------------------------------------------------------------------'
PythonVersion = sys.version_info[0];
with open('httplib.h') as f:
lines = f.readlines()
inImplementation = False
os.makedirs('out', exist_ok=True)
if PythonVersion < 3:
os.makedirs('out')
else:
os.makedirs('out', exist_ok=True)
with open('out/httplib.h', 'w') as fh:
with open('out/httplib.cc', 'w') as fc:
fc.write('#include "httplib.h"\n')
+8 -2
View File
@@ -1,6 +1,6 @@
#CXX = clang++
CXXFLAGS = -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits
CXXFLAGS = -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion
OPENSSL_DIR = /usr/local/opt/openssl
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
@@ -8,9 +8,15 @@ ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
all : test
./test
proxy : test_proxy
./test_proxy
test : test.cc ../httplib.h Makefile cert.pem
$(CXX) -o test $(CXXFLAGS) test.cc gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) -pthread
test_proxy : test_proxy.cc ../httplib.h Makefile cert.pem
$(CXX) -o test_proxy $(CXXFLAGS) test_proxy.cc gtest/gtest-all.cc gtest/gtest_main.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) -pthread
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
@@ -21,4 +27,4 @@ cert.pem:
#c_rehash .
clean:
rm -f test *.pem *.0 *.1 *.srl
rm -f test test_proxy pem *.0 *.1 *.srl
+14 -1
View File
@@ -38,6 +38,14 @@
// when it's fused.
#include "gtest/gtest.h"
#if __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion"
#elif __GNUC__
#pragma gcc diagnostic push
#pragma gcc diagnostic ignored "-Wsign-conversion"
#endif
// The following lines pull in the real gtest *.cc files.
// Copyright 2005, Google Inc.
// All rights reserved.
@@ -9039,7 +9047,6 @@ void HasNewFatalFailureHelper::ReportTestPartResult(
//
// Author: wan@google.com (Zhanyong Wan)
namespace testing {
namespace internal {
@@ -9116,3 +9123,9 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
} // namespace internal
} // namespace testing
#if __clang__
#pragma clang diagnostic pop
#elif __GNUC__
#pragma gcc diagnostic pop
#endif
+15 -1
View File
@@ -59,6 +59,14 @@
#pragma warning(disable : 4996)
#endif
#if __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-compare"
#elif __GNUC__
#pragma gcc diagnostic push
#pragma gcc diagnostic ignored "-Wsign-compare"
#endif
// Copyright 2005, Google Inc.
// All rights reserved.
//
@@ -7311,7 +7319,7 @@ inline const char* SkipComma(const char* str) {
// the entire string if it contains no comma.
inline String GetPrefixUntilComma(const char* str) {
const char* comma = strchr(str, ',');
return comma == NULL ? String(str) : String(str, comma - str);
return comma == NULL ? String(str) : String(str, static_cast<size_t>(comma - str));
}
// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
@@ -19553,4 +19561,10 @@ bool StaticAssertTypeEq() {
#pragma warning( pop )
#endif
#if __clang__
#pragma clang diagnostic pop
#elif __GNUC__
#pragma gcc diagnostic pop
#endif
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+13
View File
@@ -0,0 +1,13 @@
FROM centos:7
ARG auth="basic"
ARG port="3128"
RUN yum install -y squid
COPY ./${auth}_squid.conf /etc/squid/squid.conf
COPY ./${auth}_passwd /etc/squid/passwd
EXPOSE ${port}
CMD ["/usr/sbin/squid", "-N"]
+1
View File
@@ -0,0 +1 @@
hello:$apr1$O6S28OBL$8dr3ixl4Mohf97hgsYvLy/
+81
View File
@@ -0,0 +1,81 @@
#
# Recommended minimum configuration:
#
# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
auth_param basic program /usr/lib64/squid/basic_ncsa_auth /etc/squid/passwd
auth_param basic realm proxy
acl authenticated proxy_auth REQUIRED
http_access allow authenticated
#
# Recommended minimum Access Permission configuration:
#
# Deny requests to certain unsafe ports
http_access deny !Safe_ports
# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports
# Only allow cachemgr access from localhost
http_access allow localhost manager
http_access deny manager
# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on "localhost" is a local user
#http_access deny to_localhost
#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#
# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
http_access allow localnet
http_access allow localhost
# And finally deny all other access to this proxy
http_access deny all
# Squid normally listens to port 3128
http_port 3128
# Uncomment and adjust the following to add a disk cache directory.
#cache_dir ufs /var/spool/squid 100 16 256
# Leave coredumps in the first cache dir
coredump_dir /var/spool/squid
#
# Add any of your own refresh_pattern entries above these.
#
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
+1
View File
@@ -0,0 +1 @@
hello:world
+81
View File
@@ -0,0 +1,81 @@
#
# Recommended minimum configuration:
#
# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN)
acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
acl localnet src fc00::/7 # RFC 4193 local private network range
acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
auth_param digest program /usr/lib64/squid/digest_file_auth /etc/squid/passwd
auth_param digest realm proxy
acl authenticated proxy_auth REQUIRED
http_access allow authenticated
#
# Recommended minimum Access Permission configuration:
#
# Deny requests to certain unsafe ports
http_access deny !Safe_ports
# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports
# Only allow cachemgr access from localhost
http_access allow localhost manager
http_access deny manager
# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on "localhost" is a local user
#http_access deny to_localhost
#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#
# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
http_access allow localnet
http_access allow localhost
# And finally deny all other access to this proxy
http_access deny all
# Squid normally listens to port 3128
http_port 3129
# Uncomment and adjust the following to add a disk cache directory.
#cache_dir ufs /var/spool/squid 100 16 256
# Leave coredumps in the first cache dir
coredump_dir /var/spool/squid
#
# Add any of your own refresh_pattern entries above these.
#
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
+22
View File
@@ -0,0 +1,22 @@
version: '2'
services:
squid_basic:
image: squid_basic
restart: always
ports:
- "3128:3128"
build:
context: ./
args:
auth: basic
squid_digest:
image: squid_digest
restart: always
ports:
- "3129:3129"
build:
context: ./
args:
auth: digest
+1
View File
@@ -0,0 +1 @@
docker-compose down --rmi all
+1
View File
@@ -0,0 +1 @@
docker-compose up -d
+879 -113
View File
File diff suppressed because it is too large Load Diff
+13 -13
View File
@@ -28,7 +28,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
@@ -40,7 +40,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
@@ -69,13 +69,13 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>C:\Program Files\OpenSSL-Win64\lib\VC;C:\Program Files\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>C:\Program Files\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files\OpenSSL-Win64\lib;$(LibraryPath)</LibraryPath>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
@@ -84,14 +84,14 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>C:\Program Files\OpenSSL-Win64\include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files\OpenSSL-Win64\lib;$(LibraryPath)</LibraryPath>
<IncludePath>$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
@@ -108,7 +108,7 @@
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>./;../</AdditionalIncludeDirectories>
@@ -118,12 +118,12 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>Ws2_32.lib;libssl.lib;libcrypto.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
@@ -144,7 +144,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
@@ -160,7 +160,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>Ws2_32.lib;libssl.lib;libcrypto.lib;libssl.lib;libcrypto.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
+303
View File
@@ -0,0 +1,303 @@
#include <future>
#include <gtest/gtest.h>
#include <httplib.h>
using namespace std;
using namespace httplib;
void ProxyTest(Client& cli, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
auto res = cli.Get("/get");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(407, res->status);
}
TEST(ProxyTest, NoSSLBasic) {
Client cli("httpbin.org");
ProxyTest(cli, true);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(ProxyTest, SSLBasic) {
SSLClient cli("httpbin.org");
ProxyTest(cli, true);
}
TEST(ProxyTest, NoSSLDigest) {
Client cli("httpbin.org");
ProxyTest(cli, false);
}
TEST(ProxyTest, SSLDigest) {
SSLClient cli("httpbin.org");
ProxyTest(cli, false);
}
#endif
// ----------------------------------------------------------------------------
void RedirectProxyText(Client& cli, const char *path, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
if (basic) {
cli.set_proxy_basic_auth("hello", "world");
} else {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
cli.set_proxy_digest_auth("hello", "world");
#endif
}
cli.set_follow_location(true);
auto res = cli.Get(path);
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
}
TEST(RedirectTest, HTTPBinNoSSLBasic) {
Client cli("httpbin.org");
RedirectProxyText(cli, "/redirect/2", true);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(RedirectTest, HTTPBinNoSSLDigest) {
Client cli("httpbin.org");
RedirectProxyText(cli, "/redirect/2", false);
}
TEST(RedirectTest, HTTPBinSSLBasic) {
SSLClient cli("httpbin.org");
RedirectProxyText(cli, "/redirect/2", true);
}
TEST(RedirectTest, HTTPBinSSLDigest) {
SSLClient cli("httpbin.org");
RedirectProxyText(cli, "/redirect/2", false);
}
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(RedirectTest, YouTubeNoSSLBasic) {
Client cli("youtube.com");
RedirectProxyText(cli, "/", true);
}
TEST(RedirectTest, YouTubeNoSSLDigest) {
Client cli("youtube.com");
RedirectProxyText(cli, "/", false);
}
TEST(RedirectTest, YouTubeSSLBasic) {
SSLClient cli("youtube.com");
RedirectProxyText(cli, "/", true);
}
TEST(RedirectTest, YouTubeSSLDigest) {
SSLClient cli("youtube.com");
RedirectProxyText(cli, "/", false);
}
#endif
// ----------------------------------------------------------------------------
void BaseAuthTestFromHTTPWatch(Client& 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);
}
{
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);
}
{
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);
}
{
cli.set_basic_auth("hello", "bad");
auto res = cli.Get("/basic-auth/hello/world");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(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);
}
}
TEST(BaseAuthTest, NoSSL) {
Client cli("httpbin.org");
BaseAuthTestFromHTTPWatch(cli);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(BaseAuthTest, SSL) {
SSLClient cli("httpbin.org");
BaseAuthTestFromHTTPWatch(cli);
}
#endif
// ----------------------------------------------------------------------------
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
void DigestAuthTestFromHTTPWatch(Client& 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);
}
{
std::vector<std::string> paths = {
"/digest-auth/auth/hello/world/MD5",
"/digest-auth/auth/hello/world/SHA-256",
"/digest-auth/auth/hello/world/SHA-512",
"/digest-auth/auth-int/hello/world/MD5",
};
cli.set_digest_auth("hello", "world");
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);
}
cli.set_digest_auth("hello", "bad");
for (auto path : paths) {
auto res = cli.Get(path.c_str());
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(400, res->status);
}
cli.set_digest_auth("bad", "world");
for (auto path : paths) {
auto res = cli.Get(path.c_str());
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(400, res->status);
}
}
}
TEST(DigestAuthTest, SSL) {
SSLClient cli("httpbin.org");
DigestAuthTestFromHTTPWatch(cli);
}
TEST(DigestAuthTest, NoSSL) {
Client cli("httpbin.org");
DigestAuthTestFromHTTPWatch(cli);
}
#endif
// ----------------------------------------------------------------------------
void KeepAliveTest(Client& cli, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
if (basic) {
cli.set_proxy_basic_auth("hello", "world");
} else {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
cli.set_proxy_digest_auth("hello", "world");
#endif
}
cli.set_keep_alive_max_count(4);
cli.set_follow_location(true);
cli.set_digest_auth("hello", "world");
std::vector<Request> requests;
Get(requests, "/get");
Get(requests, "/redirect/2");
std::vector<std::string> paths = {
"/digest-auth/auth/hello/world/MD5",
"/digest-auth/auth/hello/world/SHA-256",
"/digest-auth/auth/hello/world/SHA-512",
"/digest-auth/auth-int/hello/world/MD5",
};
for (auto path : paths) {
Get(requests, path.c_str());
}
{
int count = 100;
while (count--) {
Get(requests, "/get");
}
}
std::vector<Response> responses;
auto ret = cli.send(requests, responses);
ASSERT_TRUE(ret == true);
ASSERT_TRUE(requests.size() == responses.size());
size_t i = 0;
{
auto &res = responses[i++];
EXPECT_EQ(200, res.status);
}
{
auto &res = responses[i++];
EXPECT_EQ(200, res.status);
}
{
int count = paths.size();
while (count--) {
auto &res = responses[i++];
EXPECT_EQ("{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n", res.body);
EXPECT_EQ(200, res.status);
}
}
for (; i < responses.size(); i++) {
auto &res = responses[i];
EXPECT_EQ(200, res.status);
}
}
TEST(KeepAliveTest, NoSSLWithBasic) {
Client cli("httpbin.org");
KeepAliveTest(cli, true);
}
TEST(KeepAliveTest, SSLWithBasic) {
SSLClient cli("httpbin.org");
KeepAliveTest(cli, true);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(KeepAliveTest, NoSSLWithDigest) {
Client cli("httpbin.org");
KeepAliveTest(cli, false);
}
TEST(KeepAliveTest, SSLWithDigest) {
SSLClient cli("httpbin.org");
KeepAliveTest(cli, false);
}
#endif
+1
View File
@@ -0,0 +1 @@
abcde