Compare commits

..

54 Commits

Author SHA1 Message Date
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
yhirose
39c7bba7b9 Code cleanup 2019-12-17 13:05:08 -05:00
yhirose
f2476f21fc Fixed URL encoding problem when sending a request to proxy 2019-12-17 12:58:25 -05:00
yhirose
c776454c84 Updated README 2019-12-15 20:31:36 -05:00
yhirose
82a5ac735f Merge pull request #290 from yhirose/interface
Fix #285. Added set_interface method on client
2019-12-15 18:02:51 -05:00
yhirose
08bf806e92 Updated README 2019-12-15 17:55:08 -05:00
yhirose
9a41b16cbb Fix #285. Added set_interface method on client 2019-12-15 17:44:00 -05:00
yhirose
10759f0a38 Updated README 2019-12-15 00:21:32 -05:00
yhirose
58b2814fda Format code 2019-12-14 23:50:53 -05:00
yhirose
260422b7d7 Format code 2019-12-14 23:46:11 -05:00
yhirose
d2c7b447d5 Fix #289: Fixed build problem with Visual C++ 2019-12-13 09:12:50 -05:00
yhirose
72b20c08da Better API names 2019-12-13 06:56:00 -05:00
yhirose
afd6d5f9dc Removed compress parameter and added compress method on client 2019-12-12 23:09:59 -05:00
yhirose
e5827ad16f Fixed build error 2019-12-12 23:09:34 -05:00
yhirose
5324b3d661 Improved multipart form data interface 2019-12-12 22:48:09 -05:00
yhirose
151ccba57e Code cleanup 2019-12-12 21:50:12 -05:00
yhirose
69a28d50f6 Fix #287 2019-12-12 12:50:45 -05:00
Yuji Hirose
048f31109f Updated README 2019-12-10 13:14:23 -05:00
Yuji Hirose
d064fb7ff2 Fixed warning 2019-12-10 13:08:07 -05:00
Yuji Hirose
3c2736bb2a Fixed regex syntax error 2019-12-10 13:07:49 -05:00
Yuji Hirose
fd4e1b4112 Fix #266 2019-12-10 12:10:14 -05:00
yhirose
f6a2365ca5 Fix #282 2019-12-06 12:21:15 -05:00
yhirose
df1ff7510b Made code more readable 2019-12-06 12:02:08 -05:00
yhirose
379905bd34 Merge branch 'whitespace-and-libcxx-compat' of https://github.com/matvore/cpp-httplib 2019-12-06 09:51:21 -05:00
yhirose
66719ae3d4 Merge pull request #283 from barryam3/noexcept
Remove use of exceptions.
2019-12-05 21:32:06 -05:00
Matthew DeVore
bc9251ea49 Work around incompatibility in <regex> in libc++
libc++ (the implementation of the C++ standard library usually used by
Clang) throws an exception for the regex used by parse_headers before
this patch for certain strings. Work around this by simplifying the
regex and parsing the header lines "by hand" partially. I have repro'd
this problem with Xcode 11.1 which I believe uses libc++ version 8.

This may be a bug in libc++ as I can't see why the regex would result in
asymptotic run-time complexity for any strings. However, it may take a
while for libc++ to be fixed and for everyone to migrate to it, so it
makes sense to work around it in this codebase for now.
2019-12-05 17:14:16 -08:00
Matthew DeVore
a9e942d755 Properly trim whitespace from headers
HTTP Whitespace and regex whitespace are not the same, so we can't use
\s in regexes when parsing HTTP headers. Instead, explicitly specify
what is considered whitespace in the regex.
2019-12-05 17:14:16 -08:00
Barry McNamara
e1785d6723 Remove use of exceptions. 2019-12-05 15:56:55 -08:00
yhirose
b9539b8921 Fixed build errors 2019-12-03 10:30:07 -05:00
yhirose
4c93b973ff Fixed typo in README 2019-12-02 09:50:52 -05:00
yhirose
033bc35723 Improve multipart content reader interface 2019-12-02 07:11:12 -05:00
22 changed files with 1550 additions and 442 deletions

5
.clang-format Normal file
View File

@@ -0,0 +1,5 @@
BasedOnStyle: LLVM
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
Cpp11BracedListStyle: true

2
.gitignore vendored
View File

@@ -6,8 +6,10 @@ example/hello
example/simplesvr
example/benchmark
example/redirect
example/upload
example/*.pem
test/test
test/test_proxy
test/test.xcodeproj/xcuser*
test/test.xcodeproj/*/xcuser*
test/*.pem

View File

@@ -1,6 +1,7 @@
# Environment
language: cpp
os:
- linux
- osx
# Compiler selection

View File

@@ -51,6 +51,11 @@ svr.listen_after_bind();
```cpp
svr.set_base_dir("./www"); // This is same as `svr.set_base_dir("./www", "/")`;
// 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
@@ -62,6 +67,25 @@ 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 |
### Logging
```cpp
@@ -74,7 +98,7 @@ svr.set_logger([](const auto& req, const auto& res) {
```cpp
svr.set_error_handler([](const auto& req, auto& res) {
const char* fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
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");
@@ -119,15 +143,14 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
svr.Post("/content_receiver",
[&](const Request &req, Response &res, const ContentReader &content_reader) {
if (req.is_multipart_form_data()) {
MultipartFiles files;
MultipartFormDataItems files;
content_reader(
[&](const std::string &name, const char *data, size_t data_length) {
auto &file = files.find(name)->second;
file.content.append(data, data_length);
[&](const MultipartFormData &file) {
files.push_back(file);
return true;
},
[&](const std::string &name, const MultipartFile &file) {
files.emplace(name, file);
[&](const char *data, size_t data_length) {
files.back().content.append(data, data_length);
return true;
});
} else {
@@ -156,7 +179,7 @@ svr.Get("/chunked", [&](const Request& req, Response& res) {
});
```
### Default thread pool supporet
### Default thread pool support
Set thread count to 8:
@@ -302,7 +325,7 @@ 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
```
### With Progress Callback
@@ -324,18 +347,32 @@ std::shared_ptr<httplib::Response> res =
This feature was contributed by [underscorediscovery](https://github.com/yhirose/cpp-httplib/pull/23).
### Basic Authentication
### Authentication
```cpp
httplib::Client cli("httplib.org");
// Basic Authentication
cli.set_basic_auth("user", "pass");
auto res = cli.Get("/basic-auth/hello/world", {
httplib::make_basic_authentication_header("hello", "world")
});
// res->status should be 200
// res->body should be "{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n".
// Digest Authentication
cli.set_digest_auth("user", "pass");
```
NOTE: OpenSSL is required for Digest Authentication.
### Proxy server support
```cpp
cli.set_proxy("host", port);
// Basic Authentication
cli.set_proxy_basic_auth("user", "pass");
// Digest Authentication
cli.set_proxy_digest_auth("user", "pass");
```
NOTE: OpenSSL is required for Digest Authentication.
### Range
```cpp
@@ -381,11 +418,19 @@ httplib::Client cli("yahoo.com");
auto res = cli.Get("/");
res->status; // 301
cli.follow_location(true);
cli.set_follow_location(true);
res = cli.Get("/");
res->status; // 200
```
### Use a specitic network interface
NOTE: This feature is not available on Windows, yet.
```cpp
cli.set_interface("eth0"); // Interface name, IP address or host name
```
OpenSSL Support
---------------
@@ -417,10 +462,26 @@ The server applies gzip compression to the following MIME type contents:
* application/xml
* application/xhtml+xml
### Compress content on client
```c++
cli.set_compress(true);
res = cli.Post("/resource/foo", "...", "text/plain");
```
Split httplib.h into .h and .cc
-------------------------------
```bash
> python3 split.py
> ls out
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++ 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).
License
-------

View File

@@ -33,4 +33,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 *.pem
rm server client hello simplesvr upload redirect benchmark *.pem

View File

@@ -44,14 +44,10 @@ int main(void) {
#endif
// Run servers
auto httpThread = std::thread([&]() {
http.listen("localhost", 8080);
});
auto httpThread = std::thread([&]() { http.listen("localhost", 8080); });
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto httpsThread = std::thread([&]() {
https.listen("localhost", 8081);
});
auto httpsThread = std::thread([&]() { https.listen("localhost", 8081); });
#endif
httpThread.join();

View File

@@ -27,7 +27,7 @@ string dump_headers(const Headers &headers) {
return s;
}
string dump_multipart_files(const MultipartFiles &files) {
string dump_multipart_files(const MultipartFormDataMap &files) {
string s;
char buf[BUFSIZ];
@@ -46,10 +46,7 @@ string dump_multipart_files(const MultipartFiles &files) {
snprintf(buf, sizeof(buf), "content type: %s\n", file.content_type.c_str());
s += buf;
snprintf(buf, sizeof(buf), "text offset: %lu\n", file.offset);
s += buf;
snprintf(buf, sizeof(buf), "text length: %lu\n", file.length);
snprintf(buf, sizeof(buf), "text length: %lu\n", file.content.size());
s += buf;
s += "----------------\n";

View File

@@ -5,13 +5,13 @@
// MIT License
//
#include <fstream>
#include <httplib.h>
#include <iostream>
#include <fstream>
using namespace httplib;
using namespace std;
const char* html = R"(
const char *html = R"(
<form id="formElem">
<input type="file" name="file" accept="image/*">
<input type="submit">
@@ -35,12 +35,13 @@ int main(void) {
res.set_content(html, "text/html");
});
svr.Post("/post", [](const Request & req, Response &res) {
svr.Post("/post", [](const Request &req, Response &res) {
auto file = req.get_file_value("file");
cout << "file: " << file.offset << ":" << file.length << ":" << file.filename << endl;
cout << "file length: " << file.content.length() << ":" << file.filename
<< endl;
ofstream ofs(file.filename, ios::binary);
ofs << req.body.substr(file.offset, file.length);
ofs << file.content;
res.set_content("done", "text/plain");
});

1116
httplib.h

File diff suppressed because it is too large Load Diff

24
split.py Normal file
View File

@@ -0,0 +1,24 @@
import os
border = '// ----------------------------------------------------------------------------'
with open('httplib.h') as f:
lines = f.readlines()
inImplementation = False
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')
fc.write('namespace httplib {\n')
for line in lines:
isBorderLine = border in line
if isBorderLine:
inImplementation = not inImplementation
else:
if inImplementation:
fc.write(line.replace('inline ', ''))
pass
else:
fh.write(line)
pass
fc.write('} // namespace httplib\n')

View File

@@ -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

View File

@@ -30,9 +30,12 @@ const std::string JSON_DATA = "{\"hello\":\"world\"}";
const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
MultipartFile& get_file_value(MultipartFiles &files, const char *key) {
auto it = files.find(key);
if (it != files.end()) { return it->second; }
MultipartFormData &get_file_value(MultipartFormDataItems &files,
const char *key) {
auto it = std::find_if(
files.begin(), files.end(),
[&](const MultipartFormData &file) { return file.name == key; });
if (it != files.end()) { return *it; }
throw std::runtime_error("invalid mulitpart form data name error");
}
@@ -201,15 +204,15 @@ TEST(ParseHeaderValueTest, Range) {
TEST(ChunkedEncodingTest, FromHTTPWatch) {
auto host = "www.httpwatch.com";
auto sec = 2;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(2);
auto res =
cli.Get("/httpgallery/chunked/chunkedimage.aspx?0.4153841143030137");
@@ -224,15 +227,15 @@ TEST(ChunkedEncodingTest, FromHTTPWatch) {
TEST(ChunkedEncodingTest, WithContentReceiver) {
auto host = "www.httpwatch.com";
auto sec = 2;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(2);
std::string body;
auto res =
@@ -252,15 +255,15 @@ TEST(ChunkedEncodingTest, WithContentReceiver) {
TEST(ChunkedEncodingTest, WithResponseHandlerAndContentReceiver) {
auto host = "www.httpwatch.com";
auto sec = 2;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(2);
std::string body;
auto res = cli.Get(
@@ -284,15 +287,15 @@ TEST(ChunkedEncodingTest, WithResponseHandlerAndContentReceiver) {
TEST(RangeTest, FromHTTPBin) {
auto host = "httpbin.org";
auto sec = 5;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(5);
{
httplib::Headers headers;
@@ -344,15 +347,15 @@ TEST(RangeTest, FromHTTPBin) {
TEST(ConnectionErrorTest, InvalidHost) {
auto host = "-abcde.com";
auto sec = 2;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(2);
auto res = cli.Get("/");
ASSERT_TRUE(res == nullptr);
@@ -360,15 +363,15 @@ TEST(ConnectionErrorTest, InvalidHost) {
TEST(ConnectionErrorTest, InvalidPort) {
auto host = "localhost";
auto sec = 2;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 44380;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 8080;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(2);
auto res = cli.Get("/");
ASSERT_TRUE(res == nullptr);
@@ -376,15 +379,15 @@ TEST(ConnectionErrorTest, InvalidPort) {
TEST(ConnectionErrorTest, Timeout) {
auto host = "google.com";
auto sec = 2;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 44380;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 8080;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(2);
auto res = cli.Get("/");
ASSERT_TRUE(res == nullptr);
@@ -392,15 +395,15 @@ TEST(ConnectionErrorTest, Timeout) {
TEST(CancelTest, NoCancel) {
auto host = "httpbin.org";
auto sec = 5;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(5);
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return true; });
ASSERT_TRUE(res != nullptr);
@@ -410,31 +413,31 @@ TEST(CancelTest, NoCancel) {
TEST(CancelTest, WithCancelSmallPayload) {
auto host = "httpbin.org";
auto sec = 5;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
auto res = cli.Get("/range/32", [](uint64_t, uint64_t) { return false; });
cli.set_timeout_sec(5);
ASSERT_TRUE(res == nullptr);
}
TEST(CancelTest, WithCancelLargePayload) {
auto host = "httpbin.org";
auto sec = 5;
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
auto port = 443;
httplib::SSLClient cli(host, port, sec);
httplib::SSLClient cli(host, port);
#else
auto port = 80;
httplib::Client cli(host, port, sec);
httplib::Client cli(host, port);
#endif
cli.set_timeout_sec(5);
uint32_t count = 0;
httplib::Headers headers;
@@ -469,8 +472,78 @@ TEST(BaseAuthTest, FromHTTPWatch) {
"{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n");
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(res->body,
"{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n");
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);
}
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(DigestAuthTest, FromHTTPWatch) {
auto host = "httpbin.org";
auto port = 443;
httplib::SSLClient cli(host, port);
{
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-init/hello/world/MD5",
"/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(res->body,
"{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n");
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);
}
}
}
#endif
TEST(AbsoluteRedirectTest, Redirect) {
auto host = "httpbin.org";
@@ -480,7 +553,7 @@ TEST(AbsoluteRedirectTest, Redirect) {
httplib::Client cli(host);
#endif
cli.follow_location(true);
cli.set_follow_location(true);
auto res = cli.Get("/absolute-redirect/3");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
@@ -495,7 +568,7 @@ TEST(RedirectTest, Redirect) {
httplib::Client cli(host);
#endif
cli.follow_location(true);
cli.set_follow_location(true);
auto res = cli.Get("/redirect/3");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
@@ -510,7 +583,7 @@ TEST(RelativeRedirectTest, Redirect) {
httplib::Client cli(host);
#endif
cli.follow_location(true);
cli.set_follow_location(true);
auto res = cli.Get("/relative-redirect/3");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
@@ -525,7 +598,7 @@ TEST(TooManyRedirectTest, Redirect) {
httplib::Client cli(host);
#endif
cli.follow_location(true);
cli.set_follow_location(true);
auto res = cli.Get("/redirect/21");
ASSERT_TRUE(res == nullptr);
}
@@ -538,7 +611,7 @@ TEST(YahooRedirectTest, Redirect) {
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(301, res->status);
cli.follow_location(true);
cli.set_follow_location(true);
res = cli.Get("/");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
@@ -546,7 +619,7 @@ TEST(YahooRedirectTest, Redirect) {
TEST(HttpsToHttpRedirectTest, Redirect) {
httplib::SSLClient cli("httpbin.org");
cli.follow_location(true);
cli.set_follow_location(true);
auto res =
cli.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
ASSERT_TRUE(res != nullptr);
@@ -574,6 +647,7 @@ protected:
virtual void SetUp() {
svr_.set_base_dir("./www");
svr_.set_base_dir("./www2", "/mount");
svr_.set_file_extension_and_mimetype_mapping("abcde", "text/abcde");
svr_.Get("/hi",
[&](const Request & /*req*/, Response &res) {
@@ -757,19 +831,19 @@ protected:
EXPECT_EQ("5", req.get_header_value("Content-Length"));
})
.Post("/content_receiver",
[&](const Request & req, Response &res, const ContentReader &content_reader) {
[&](const Request &req, Response &res,
const ContentReader &content_reader) {
if (req.is_multipart_form_data()) {
MultipartFiles files;
MultipartFormDataItems files;
content_reader(
[&](const std::string &name, const char *data, size_t data_length) {
auto &file = files.find(name)->second;
file.content.append(data, data_length);
return true;
},
[&](const std::string &name, const MultipartFile &file) {
files.emplace(name, file);
return true;
});
[&](const MultipartFormData &file) {
files.push_back(file);
return true;
},
[&](const char *data, size_t data_length) {
files.back().content.append(data, data_length);
return true;
});
EXPECT_EQ(5u, files.size());
@@ -831,6 +905,12 @@ protected:
EXPECT_EQ(body, "content");
res.set_content(body, "text/plain");
})
.Post("/query-string-and-body",
[&](const Request &req, Response & /*res*/) {
ASSERT_TRUE(req.has_param("key"));
EXPECT_EQ(req.get_param_value("key"), "value");
EXPECT_EQ(req.body, "content");
})
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
.Get("/gzip",
[&](const Request & /*req*/, Response &res) {
@@ -1082,6 +1162,14 @@ TEST_F(ServerTest, GetMethodOutOfBaseDirMount2) {
EXPECT_EQ(404, res->status);
}
TEST_F(ServerTest, UserDefinedMIMETypeMapping) {
auto res = cli_.Get("/dir/test.abcde");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
EXPECT_EQ("text/abcde", res->get_header_value("Content-Type"));
EXPECT_EQ("abcde\n", res->body);
}
TEST_F(ServerTest, InvalidBaseDirMount) {
EXPECT_EQ(false, svr_.set_base_dir("./www3", "invalid_mount_point"));
}
@@ -1357,7 +1445,7 @@ TEST_F(ServerTest, GetStreamedWithRangeMultipart) {
}
TEST_F(ServerTest, GetStreamedEndless) {
size_t offset = 0;
uint64_t offset = 0;
auto res = cli_.Get("/streamed-cancel",
[&](const char * /*data*/, uint64_t data_length) {
if (offset < 100) {
@@ -1492,12 +1580,13 @@ TEST_F(ServerTest, PutWithContentProvider) {
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
TEST_F(ServerTest, PutWithContentProviderWithGzip) {
cli_.set_compress(true);
auto res = cli_.Put(
"/put", 3,
[](size_t /*offset*/, size_t /*length*/, DataSink sink) {
sink("PUT", 3);
},
"text/plain", true);
"text/plain");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
@@ -1505,7 +1594,8 @@ TEST_F(ServerTest, PutWithContentProviderWithGzip) {
}
TEST_F(ServerTest, PutLargeFileWithGzip) {
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain", true);
cli_.set_compress(true);
auto res = cli_.Put("/put-large", LARGE_DATA, "text/plain");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
@@ -1578,7 +1668,8 @@ TEST_F(ServerTest, PostMulitpartFilsContentReceiver) {
}
TEST_F(ServerTest, PostContentReceiverGzip) {
auto res = cli_.Post("/content_receiver", "content", "text/plain", true);
cli_.set_compress(true);
auto res = cli_.Post("/content_receiver", "content", "text/plain");
ASSERT_TRUE(res != nullptr);
ASSERT_EQ(200, res->status);
ASSERT_EQ("content", res->body);
@@ -1598,6 +1689,12 @@ TEST_F(ServerTest, PatchContentReceiver) {
ASSERT_EQ("content", res->body);
}
TEST_F(ServerTest, PostQueryStringAndBody) {
auto res = cli_.Post("/query-string-and-body?key=value", "content", "text/plain");
ASSERT_TRUE(res != nullptr);
ASSERT_EQ(200, res->status);
}
TEST_F(ServerTest, HTTP2Magic) {
Request req;
req.method = "PRI";
@@ -1610,6 +1707,7 @@ TEST_F(ServerTest, HTTP2Magic) {
ASSERT_TRUE(ret);
EXPECT_EQ(400, res->status);
}
TEST_F(ServerTest, KeepAlive) {
cli_.set_keep_alive_max_count(4);
@@ -1759,13 +1857,94 @@ TEST_F(ServerTest, MultipartFormDataGzip) {
{"key2", "--abcdefg123", "", ""},
};
auto res = cli_.Post("/gzipmultipart", items, true);
cli_.set_compress(true);
auto res = cli_.Post("/gzipmultipart", items);
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
}
#endif
// Sends a raw request to a server listening at HOST:PORT.
static bool send_request(time_t read_timeout_sec, const std::string &req) {
auto client_sock = detail::create_client_socket(HOST, PORT, /*timeout_sec=*/5,
std::string());
if (client_sock == INVALID_SOCKET) { return false; }
return detail::process_and_close_socket(
true, client_sock, 1, read_timeout_sec, 0,
[&](Stream &strm, bool /*last_connection*/, bool &
/*connection_close*/) -> bool {
if (req.size() !=
static_cast<size_t>(strm.write(req.data(), req.size()))) {
return false;
}
char buf[512];
detail::stream_line_reader line_reader(strm, buf, sizeof(buf));
while (line_reader.getline()) {}
return true;
});
}
TEST(ServerRequestParsingTest, TrimWhitespaceFromHeaderValues) {
Server svr;
std::string header_value;
svr.Get("/validate-ws-in-headers", [&](const Request &req, Response &res) {
header_value = req.get_header_value("foo");
res.set_content("ok", "text/plain");
});
thread t = thread([&] { svr.listen(HOST, PORT); });
while (!svr.is_running()) {
msleep(1);
}
// Only space and horizontal tab are whitespace. Make sure other whitespace-
// like characters are not treated the same - use vertical tab and escape.
const std::string req = "GET /validate-ws-in-headers HTTP/1.1\r\n"
"foo: \t \v bar \e\t \r\n"
"Connection: close\r\n"
"\r\n";
ASSERT_TRUE(send_request(5, req));
svr.stop();
t.join();
EXPECT_EQ(header_value, "\v bar \e");
}
TEST(ServerRequestParsingTest, ReadHeadersRegexComplexity) {
Server svr;
svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
res.set_content("ok", "text/plain");
});
// Server read timeout must be longer than the client read timeout for the
// bug to reproduce, probably to force the server to process a request
// without a trailing blank line.
const time_t client_read_timeout_sec = 1;
svr.set_read_timeout(client_read_timeout_sec + 1, 0);
bool listen_thread_ok = false;
thread t = thread([&] { listen_thread_ok = svr.listen(HOST, PORT); });
while (!svr.is_running()) {
msleep(1);
}
// A certain header line causes an exception if the header property is parsed
// naively with a single regex. This occurs with libc++ but not libstdc++.
const std::string req =
"GET /hi HTTP/1.1\r\n"
" : "
" ";
ASSERT_TRUE(send_request(client_read_timeout_sec, req));
svr.stop();
t.join();
EXPECT_TRUE(listen_thread_ok);
}
class ServerTestWithAI_PASSIVE : public ::testing::Test {
protected:
ServerTestWithAI_PASSIVE()
@@ -1961,9 +2140,10 @@ TEST(SSLClientServerTest, ClientCertPresent) {
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
msleep(1);
httplib::SSLClient cli(HOST, PORT, 30, CLIENT_CERT_FILE,
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE,
CLIENT_PRIVATE_KEY_FILE);
auto res = cli.Get("/test");
cli.set_timeout_sec(30);
ASSERT_TRUE(res != nullptr);
ASSERT_EQ(200, res->status);
@@ -1980,8 +2160,9 @@ TEST(SSLClientServerTest, ClientCertMissing) {
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
msleep(1);
httplib::SSLClient cli(HOST, PORT, 30);
httplib::SSLClient cli(HOST, PORT);
auto res = cli.Get("/test");
cli.set_timeout_sec(30);
ASSERT_TRUE(res == nullptr);
svr.stop();
@@ -2001,9 +2182,10 @@ TEST(SSLClientServerTest, TrustDirOptional) {
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
msleep(1);
httplib::SSLClient cli(HOST, PORT, 30, CLIENT_CERT_FILE,
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE,
CLIENT_PRIVATE_KEY_FILE);
auto res = cli.Get("/test");
cli.set_timeout_sec(30);
ASSERT_TRUE(res != nullptr);
ASSERT_EQ(200, res->status);

211
test/test_proxy.cc Normal file
View File

@@ -0,0 +1,211 @@
#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 RedirectTestHTTPBin(Client& cli, const char *path, bool basic) {
cli.set_proxy("localhost", basic ? 3128 : 3129);
if (basic) {
cli.set_proxy_basic_auth("hello", "world");
} else {
cli.set_proxy_digest_auth("hello", "world");
}
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");
RedirectTestHTTPBin(cli, "/redirect/2", true);
}
TEST(RedirectTest, HTTPBinNoSSLDigest) {
Client cli("httpbin.org");
RedirectTestHTTPBin(cli, "/redirect/2", false);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(RedirectTest, HTTPBinSSLBasic) {
SSLClient cli("httpbin.org");
RedirectTestHTTPBin(cli, "/redirect/2", true);
}
TEST(RedirectTest, HTTPBinSSLDigest) {
SSLClient cli("httpbin.org");
RedirectTestHTTPBin(cli, "/redirect/2", false);
}
#endif
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
TEST(RedirectTest, YouTubeNoSSLBasic) {
Client cli("youtube.com");
RedirectTestHTTPBin(cli, "/", true);
}
TEST(RedirectTest, YouTubeNoSSLDigest) {
Client cli("youtube.com");
RedirectTestHTTPBin(cli, "/", false);
}
TEST(RedirectTest, YouTubeSSLBasic) {
SSLClient cli("youtube.com");
RedirectTestHTTPBin(cli, "/", true);
}
TEST(RedirectTest, YouTubeSSLDigest) {
SSLClient cli("youtube.com");
RedirectTestHTTPBin(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(res->body,
"{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n");
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(res->body,
"{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n");
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);
}
// ----------------------------------------------------------------------------
#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-init/hello/world/MD5",
"/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(res->body,
"{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n");
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);
}
}
}
#endif
TEST(DigestAuthTest, SSL) {
SSLClient cli("httpbin.org");
DigestAuthTestFromHTTPWatch(cli);
}
TEST(DigestAuthTest, NoSSL) {
Client cli("httpbin.org");
DigestAuthTestFromHTTPWatch(cli);
}
#endif

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"]

View File

@@ -0,0 +1 @@
hello:$apr1$O6S28OBL$8dr3ixl4Mohf97hgsYvLy/

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

View File

@@ -0,0 +1 @@
hello:world

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

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
test/test_proxy_docker/down.sh Executable file
View File

@@ -0,0 +1 @@
docker-compose down --rmi all

1
test/test_proxy_docker/up.sh Executable file
View File

@@ -0,0 +1 @@
docker-compose up -d

1
test/www/dir/test.abcde Normal file
View File

@@ -0,0 +1 @@
abcde