mirror of
https://github.com/yhirose/cpp-httplib
synced 2026-06-08 18:30:49 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 301a419c02 | |||
| fcbcbd53bd | |||
| 1bf616d653 | |||
| ba7c7dc4a3 | |||
| aa543240db | |||
| 5675cad407 | |||
| 079d3605ea | |||
| 2c6da365d9 | |||
| 38adeaf02c | |||
| b3814b2b80 | |||
| a444b612af | |||
| ed6d949f42 | |||
| d28cd3f937 | |||
| 8cc3e6c434 | |||
| 26fbc1b7c0 | |||
| 0dc653f45a | |||
| 7a58c0a430 | |||
| dabaa51a7d | |||
| a1cfc0f377 | |||
| eb4fcb5003 | |||
| ae43c96984 | |||
| 9c81693801 | |||
| 80202c9f62 | |||
| 094a6a614a |
@@ -9,6 +9,7 @@ example/redirect
|
||||
example/upload
|
||||
example/*.pem
|
||||
test/test
|
||||
test/test_proxy
|
||||
test/test.xcodeproj/xcuser*
|
||||
test/test.xcodeproj/*/xcuser*
|
||||
test/*.pem
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Environment
|
||||
language: cpp
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
# Compiler selection
|
||||
|
||||
@@ -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");
|
||||
@@ -301,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
|
||||
|
||||
@@ -325,23 +349,30 @@ This feature was contributed by [underscorediscovery](https://github.com/yhirose
|
||||
|
||||
### 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
|
||||
@@ -450,7 +481,7 @@ 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
|
||||
-------
|
||||
|
||||
@@ -190,8 +190,6 @@ struct ci {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
enum class HttpVersion { v1_0 = 0, v1_1 };
|
||||
|
||||
using Headers = std::multimap<std::string, std::string, detail::ci>;
|
||||
|
||||
using Params = std::multimap<std::string, std::string>;
|
||||
@@ -505,12 +503,13 @@ public:
|
||||
};
|
||||
#endif
|
||||
|
||||
using Logger = std::function<void(const Request &, const Response &)>;
|
||||
|
||||
class Server {
|
||||
public:
|
||||
using Handler = std::function<void(const Request &, Response &)>;
|
||||
using HandlerWithContentReader = std::function<void(
|
||||
const Request &, Response &, const ContentReader &content_reader)>;
|
||||
using Logger = std::function<void(const Request &, const Response &)>;
|
||||
|
||||
Server();
|
||||
|
||||
@@ -529,6 +528,8 @@ public:
|
||||
Server &Options(const char *pattern, Handler handler);
|
||||
|
||||
bool set_base_dir(const char *dir, const char *mount_point = nullptr);
|
||||
void set_file_extension_and_mimetype_mapping(const char *ext,
|
||||
const char *mime);
|
||||
void set_file_request_handler(Handler handler);
|
||||
|
||||
void set_error_handler(Handler handler);
|
||||
@@ -598,6 +599,7 @@ private:
|
||||
std::atomic<bool> is_running_;
|
||||
std::atomic<socket_t> svr_sock_;
|
||||
std::vector<std::pair<std::string, std::string>> base_dirs_;
|
||||
std::map<std::string, std::string> file_extension_and_mimetype_map_;
|
||||
Handler file_request_handler_;
|
||||
Handlers get_handlers_;
|
||||
Handlers post_handlers_;
|
||||
@@ -614,7 +616,9 @@ private:
|
||||
|
||||
class Client {
|
||||
public:
|
||||
explicit Client(const char *host, int port = 80, time_t timeout_sec = 300);
|
||||
explicit Client(const std::string &host, int port = 80,
|
||||
const std::string &client_cert_path = std::string(),
|
||||
const std::string &client_key_path = std::string());
|
||||
|
||||
virtual ~Client();
|
||||
|
||||
@@ -734,11 +738,15 @@ public:
|
||||
bool send(const std::vector<Request> &requests,
|
||||
std::vector<Response> &responses);
|
||||
|
||||
void set_keep_alive_max_count(size_t count);
|
||||
void set_timeout_sec(time_t timeout_sec);
|
||||
|
||||
void set_read_timeout(time_t sec, time_t usec);
|
||||
|
||||
void set_auth(const char *username, const char *password);
|
||||
void set_keep_alive_max_count(size_t count);
|
||||
|
||||
void set_basic_auth(const char *username, const char *password);
|
||||
|
||||
void set_digest_auth(const char *username, const char *password);
|
||||
|
||||
void set_follow_location(bool on);
|
||||
|
||||
@@ -746,23 +754,76 @@ public:
|
||||
|
||||
void set_interface(const char *intf);
|
||||
|
||||
void set_proxy(const char *host, int port);
|
||||
|
||||
void set_proxy_basic_auth(const char *username, const char *password);
|
||||
|
||||
void set_proxy_digest_auth(const char *username, const char *password);
|
||||
|
||||
void set_logger(Logger logger);
|
||||
|
||||
protected:
|
||||
bool process_request(Stream &strm, const Request &req, Response &res,
|
||||
bool last_connection, bool &connection_close);
|
||||
|
||||
const std::string host_;
|
||||
const int port_;
|
||||
time_t timeout_sec_;
|
||||
const std::string host_and_port_;
|
||||
size_t keep_alive_max_count_;
|
||||
time_t read_timeout_sec_;
|
||||
time_t read_timeout_usec_;
|
||||
bool follow_location_;
|
||||
std::string username_;
|
||||
std::string password_;
|
||||
bool compress_;
|
||||
|
||||
// Settings
|
||||
std::string client_cert_path_;
|
||||
std::string client_key_path_;
|
||||
|
||||
time_t timeout_sec_ = 300;
|
||||
time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND;
|
||||
time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND;
|
||||
|
||||
size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;
|
||||
|
||||
std::string basic_auth_username_;
|
||||
std::string basic_auth_password_;
|
||||
std::string digest_auth_username_;
|
||||
std::string digest_auth_password_;
|
||||
|
||||
bool follow_location_ = false;
|
||||
|
||||
bool compress_ = false;
|
||||
|
||||
std::string interface_;
|
||||
|
||||
std::string proxy_host_;
|
||||
int proxy_port_;
|
||||
|
||||
std::string proxy_basic_auth_username_;
|
||||
std::string proxy_basic_auth_password_;
|
||||
std::string proxy_digest_auth_username_;
|
||||
std::string proxy_digest_auth_password_;
|
||||
|
||||
Logger logger_;
|
||||
|
||||
void copy_settings(const Client &rhs) {
|
||||
client_cert_path_ = rhs.client_cert_path_;
|
||||
client_key_path_ = rhs.client_key_path_;
|
||||
timeout_sec_ = rhs.timeout_sec_;
|
||||
read_timeout_sec_ = rhs.read_timeout_sec_;
|
||||
read_timeout_usec_ = rhs.read_timeout_usec_;
|
||||
keep_alive_max_count_ = rhs.keep_alive_max_count_;
|
||||
basic_auth_username_ = rhs.basic_auth_username_;
|
||||
basic_auth_password_ = rhs.basic_auth_password_;
|
||||
digest_auth_username_ = rhs.digest_auth_username_;
|
||||
digest_auth_password_ = rhs.digest_auth_password_;
|
||||
follow_location_ = rhs.follow_location_;
|
||||
compress_ = rhs.compress_;
|
||||
interface_ = rhs.interface_;
|
||||
proxy_host_ = rhs.proxy_host_;
|
||||
proxy_port_ = rhs.proxy_port_;
|
||||
proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_;
|
||||
proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_;
|
||||
proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
|
||||
proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
|
||||
logger_ = rhs.logger_;
|
||||
}
|
||||
|
||||
private:
|
||||
socket_t create_client_socket() const;
|
||||
bool read_response_line(Stream &strm, Response &res);
|
||||
@@ -852,9 +913,9 @@ private:
|
||||
|
||||
class SSLClient : public Client {
|
||||
public:
|
||||
SSLClient(const char *host, int port = 443, time_t timeout_sec = 300,
|
||||
const char *client_cert_path = nullptr,
|
||||
const char *client_key_path = nullptr);
|
||||
SSLClient(const std::string &host, int port = 443,
|
||||
const std::string &client_cert_path = std::string(),
|
||||
const std::string &client_key_path = std::string());
|
||||
|
||||
virtual ~SSLClient();
|
||||
|
||||
@@ -862,6 +923,7 @@ public:
|
||||
|
||||
void set_ca_cert_path(const char *ca_ceert_file_path,
|
||||
const char *ca_cert_dir_path = nullptr);
|
||||
|
||||
void enable_server_certificate_verification(bool enabled);
|
||||
|
||||
long get_openssl_verify_result() const;
|
||||
@@ -884,6 +946,7 @@ private:
|
||||
SSL_CTX *ctx_;
|
||||
std::mutex ctx_mutex_;
|
||||
std::vector<std::string> host_components_;
|
||||
|
||||
std::string ca_cert_file_path_;
|
||||
std::string ca_cert_dir_path_;
|
||||
bool server_certificate_verification_ = false;
|
||||
@@ -1228,10 +1291,9 @@ inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool process_and_close_socket(bool is_client_request, socket_t sock,
|
||||
size_t keep_alive_max_count,
|
||||
time_t read_timeout_sec,
|
||||
time_t read_timeout_usec, T callback) {
|
||||
inline bool process_socket(bool is_client_request, socket_t sock,
|
||||
size_t keep_alive_max_count, time_t read_timeout_sec,
|
||||
time_t read_timeout_usec, T callback) {
|
||||
assert(keep_alive_max_count > 0);
|
||||
|
||||
bool ret = false;
|
||||
@@ -1257,6 +1319,16 @@ inline bool process_and_close_socket(bool is_client_request, socket_t sock,
|
||||
ret = callback(strm, true, dummy_connection_close);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool process_and_close_socket(bool is_client_request, socket_t sock,
|
||||
size_t keep_alive_max_count,
|
||||
time_t read_timeout_sec,
|
||||
time_t read_timeout_usec, T callback) {
|
||||
auto ret = process_socket(is_client_request, sock, keep_alive_max_count,
|
||||
read_timeout_sec, read_timeout_usec, callback);
|
||||
close_socket(sock);
|
||||
return ret;
|
||||
}
|
||||
@@ -1302,6 +1374,23 @@ socket_t create_socket(const char *host, int port, Fn fn,
|
||||
#ifdef _WIN32
|
||||
auto sock = WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol,
|
||||
nullptr, 0, WSA_FLAG_NO_HANDLE_INHERIT);
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
if (sock == INVALID_SOCKET) {
|
||||
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
}
|
||||
#else
|
||||
auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
#endif
|
||||
@@ -1440,8 +1529,14 @@ inline std::string get_remote_addr(socket_t sock) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
inline const char *find_content_type(const std::string &path) {
|
||||
inline const char *
|
||||
find_content_type(const std::string &path,
|
||||
const std::map<std::string, std::string> &user_data) {
|
||||
auto ext = file_extension(path);
|
||||
|
||||
auto it = user_data.find(ext);
|
||||
if (it != user_data.end()) { return it->second.c_str(); }
|
||||
|
||||
if (ext == "txt") {
|
||||
return "text/plain";
|
||||
} else if (ext == "html" || ext == "htm") {
|
||||
@@ -1464,6 +1559,8 @@ inline const char *find_content_type(const std::string &path) {
|
||||
return "application/pdf";
|
||||
} else if (ext == "js") {
|
||||
return "application/javascript";
|
||||
} else if (ext == "wasm") {
|
||||
return "application/wasm";
|
||||
} else if (ext == "xml") {
|
||||
return "application/xml";
|
||||
} else if (ext == "xhtml") {
|
||||
@@ -1475,6 +1572,7 @@ inline const char *find_content_type(const std::string &path) {
|
||||
inline const char *status_message(int status) {
|
||||
switch (status) {
|
||||
case 200: return "OK";
|
||||
case 204: return "No Content";
|
||||
case 206: return "Partial Content";
|
||||
case 301: return "Moved Permanently";
|
||||
case 302: return "Found";
|
||||
@@ -1858,17 +1956,12 @@ write_content_chunked(Stream &strm,
|
||||
template <typename T>
|
||||
inline bool redirect(T &cli, const Request &req, Response &res,
|
||||
const std::string &path) {
|
||||
Request new_req;
|
||||
new_req.method = req.method;
|
||||
Request new_req = req;
|
||||
new_req.path = path;
|
||||
new_req.headers = req.headers;
|
||||
new_req.body = req.body;
|
||||
new_req.redirect_count = req.redirect_count - 1;
|
||||
new_req.response_handler = req.response_handler;
|
||||
new_req.content_receiver = req.content_receiver;
|
||||
new_req.progress = req.progress;
|
||||
new_req.redirect_count -= 1;
|
||||
|
||||
Response new_res;
|
||||
|
||||
auto ret = cli.send(new_req, new_res);
|
||||
if (ret) { res = new_res; }
|
||||
return ret;
|
||||
@@ -1885,7 +1978,7 @@ inline std::string encode_url(const std::string &s) {
|
||||
case '\n': result += "%0A"; break;
|
||||
case '\'': result += "%27"; break;
|
||||
case ',': result += "%2C"; break;
|
||||
case ':': result += "%3A"; break;
|
||||
// case ':': result += "%3A"; break; // ok? probably...
|
||||
case ';': result += "%3B"; break;
|
||||
default:
|
||||
auto c = static_cast<uint8_t>(s[i]);
|
||||
@@ -2394,16 +2487,18 @@ inline std::pair<std::string, std::string> make_range_header(Ranges ranges) {
|
||||
|
||||
inline std::pair<std::string, std::string>
|
||||
make_basic_authentication_header(const std::string &username,
|
||||
const std::string &password) {
|
||||
const std::string &password,
|
||||
bool is_proxy = false) {
|
||||
auto field = "Basic " + detail::base64_encode(username + ":" + password);
|
||||
return std::make_pair("Authorization", field);
|
||||
auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
|
||||
return std::make_pair(key, field);
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
inline std::pair<std::string, std::string> make_digest_authentication_header(
|
||||
const Request &req, const std::map<std::string, std::string> &auth,
|
||||
size_t cnonce_count, const std::string &cnonce, const std::string &username,
|
||||
const std::string &password) {
|
||||
const std::string &password, bool is_proxy = false) {
|
||||
using namespace std;
|
||||
|
||||
string nc;
|
||||
@@ -2420,10 +2515,11 @@ inline std::pair<std::string, std::string> make_digest_authentication_header(
|
||||
qop = "auth";
|
||||
}
|
||||
|
||||
std::string algo = "MD5";
|
||||
if (auth.find("algorithm") != auth.end()) { algo = auth.at("algorithm"); }
|
||||
|
||||
string response;
|
||||
{
|
||||
auto algo = auth.at("algorithm");
|
||||
|
||||
auto H = algo == "SHA-256"
|
||||
? detail::SHA_256
|
||||
: algo == "SHA-512" ? detail::SHA_512 : detail::MD5;
|
||||
@@ -2439,25 +2535,26 @@ inline std::pair<std::string, std::string> make_digest_authentication_header(
|
||||
|
||||
auto field = "Digest username=\"hello\", realm=\"" + auth.at("realm") +
|
||||
"\", nonce=\"" + auth.at("nonce") + "\", uri=\"" + req.path +
|
||||
"\", algorithm=" + auth.at("algorithm") + ", qop=" + qop +
|
||||
", nc=\"" + nc + "\", cnonce=\"" + cnonce + "\", response=\"" +
|
||||
response + "\"";
|
||||
"\", algorithm=" + algo + ", qop=" + qop + ", nc=\"" + nc +
|
||||
"\", cnonce=\"" + cnonce + "\", response=\"" + response + "\"";
|
||||
|
||||
return make_pair("Authorization", field);
|
||||
auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
|
||||
return std::make_pair(key, field);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline int
|
||||
parse_www_authenticate(const httplib::Response &res,
|
||||
std::map<std::string, std::string> &digest_auth) {
|
||||
if (res.has_header("WWW-Authenticate")) {
|
||||
inline bool parse_www_authenticate(const httplib::Response &res,
|
||||
std::map<std::string, std::string> &auth,
|
||||
bool is_proxy) {
|
||||
auto key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
|
||||
if (res.has_header(key)) {
|
||||
static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
|
||||
auto s = res.get_header_value("WWW-Authenticate");
|
||||
auto s = res.get_header_value(key);
|
||||
auto pos = s.find(' ');
|
||||
if (pos != std::string::npos) {
|
||||
auto type = s.substr(0, pos);
|
||||
if (type == "Basic") {
|
||||
return 1;
|
||||
return false;
|
||||
} else if (type == "Digest") {
|
||||
s = s.substr(pos + 1);
|
||||
auto beg = std::sregex_iterator(s.begin(), s.end(), re);
|
||||
@@ -2466,13 +2563,13 @@ parse_www_authenticate(const httplib::Response &res,
|
||||
auto key = s.substr(m.position(1), m.length(1));
|
||||
auto val = m.length(2) > 0 ? s.substr(m.position(2), m.length(2))
|
||||
: s.substr(m.position(3), m.length(3));
|
||||
digest_auth[key] = val;
|
||||
auth[key] = val;
|
||||
}
|
||||
return 2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/440133/how-do-i-create-a-random-alpha-numeric-string-in-c/440240#answer-440240
|
||||
@@ -2774,6 +2871,11 @@ inline bool Server::set_base_dir(const char *dir, const char *mount_point) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Server::set_file_extension_and_mimetype_mapping(const char *ext,
|
||||
const char *mime) {
|
||||
file_extension_and_mimetype_map_[ext] = mime;
|
||||
}
|
||||
|
||||
inline void Server::set_file_request_handler(Handler handler) {
|
||||
file_request_handler_ = std::move(handler);
|
||||
}
|
||||
@@ -2932,7 +3034,7 @@ inline bool Server::write_response(Stream &strm, bool last_connection,
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_ZLIB_SUPPORT
|
||||
// TODO: 'Accpet-Encoding' has gzip, not gzip;q=0
|
||||
// TODO: 'Accept-Encoding' has gzip, not gzip;q=0
|
||||
const auto &encodings = req.get_header_value("Accept-Encoding");
|
||||
if (encodings.find("gzip") != std::string::npos &&
|
||||
detail::can_compress(res.get_header_value("Content-Type"))) {
|
||||
@@ -3092,7 +3194,8 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
|
||||
|
||||
if (detail::is_file(path)) {
|
||||
detail::read_file(path, res.body);
|
||||
auto type = detail::find_content_type(path);
|
||||
auto type =
|
||||
detail::find_content_type(path, file_extension_and_mimetype_map_);
|
||||
if (type) { res.set_header("Content-Type", type); }
|
||||
res.status = 200;
|
||||
if (file_request_handler_) { file_request_handler_(req, res); }
|
||||
@@ -3355,19 +3458,22 @@ inline bool Server::process_and_close_socket(socket_t sock) {
|
||||
}
|
||||
|
||||
// HTTP client implementation
|
||||
inline Client::Client(const char *host, int port, time_t timeout_sec)
|
||||
: host_(host), port_(port), timeout_sec_(timeout_sec),
|
||||
inline Client::Client(const std::string &host, int port,
|
||||
const std::string &client_cert_path,
|
||||
const std::string &client_key_path)
|
||||
: host_(host), port_(port),
|
||||
host_and_port_(host_ + ":" + std::to_string(port_)),
|
||||
keep_alive_max_count_(CPPHTTPLIB_KEEPALIVE_MAX_COUNT),
|
||||
read_timeout_sec_(CPPHTTPLIB_READ_TIMEOUT_SECOND),
|
||||
read_timeout_usec_(CPPHTTPLIB_READ_TIMEOUT_USECOND),
|
||||
follow_location_(false), compress_(false) {}
|
||||
client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
|
||||
|
||||
inline Client::~Client() {}
|
||||
|
||||
inline bool Client::is_valid() const { return true; }
|
||||
|
||||
inline socket_t Client::create_client_socket() const {
|
||||
if (!proxy_host_.empty()) {
|
||||
return detail::create_client_socket(proxy_host_.c_str(), proxy_port_,
|
||||
timeout_sec_, interface_);
|
||||
}
|
||||
return detail::create_client_socket(host_.c_str(), port_, timeout_sec_,
|
||||
interface_);
|
||||
}
|
||||
@@ -3396,54 +3502,104 @@ inline bool Client::send(const Request &req, Response &res) {
|
||||
auto sock = create_client_socket();
|
||||
if (sock == INVALID_SOCKET) { return false; }
|
||||
|
||||
auto ret = process_and_close_socket(
|
||||
sock, 1, [&](Stream &strm, bool last_connection, bool &connection_close) {
|
||||
return process_request(strm, req, res, last_connection,
|
||||
connection_close);
|
||||
});
|
||||
|
||||
if (ret && follow_location_ && (300 < res.status && res.status < 400)) {
|
||||
ret = redirect(req, res);
|
||||
}
|
||||
|
||||
if (ret && !username_.empty() && !password_.empty() && res.status == 401) {
|
||||
int type;
|
||||
std::map<std::string, std::string> digest_auth;
|
||||
|
||||
if ((type = parse_www_authenticate(res, digest_auth)) > 0) {
|
||||
std::pair<std::string, std::string> header;
|
||||
|
||||
if (type == 1) {
|
||||
header = make_basic_authentication_header(username_, password_);
|
||||
} else if (type == 2) {
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
size_t cnonce_count = 1;
|
||||
auto cnonce = random_string(10);
|
||||
// CONNECT
|
||||
if (is_ssl() && !proxy_host_.empty()) {
|
||||
Response res2;
|
||||
if (!detail::process_socket(
|
||||
true, sock, 1, read_timeout_sec_, read_timeout_usec_,
|
||||
[&](Stream &strm, bool /*last_connection*/,
|
||||
bool &connection_close) {
|
||||
Request req2;
|
||||
req2.method = "CONNECT";
|
||||
req2.path = host_and_port_;
|
||||
return process_request(strm, req2, res2, false, connection_close);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
header = make_digest_authentication_header(
|
||||
req, digest_auth, cnonce_count, cnonce, username_, password_);
|
||||
#endif
|
||||
if (res2.status == 407) {
|
||||
if (!proxy_digest_auth_username_.empty() &&
|
||||
!proxy_digest_auth_password_.empty()) {
|
||||
std::map<std::string, std::string> auth;
|
||||
if (parse_www_authenticate(res2, auth, true)) {
|
||||
detail::close_socket(sock);
|
||||
sock = create_client_socket();
|
||||
if (sock == INVALID_SOCKET) { return false; }
|
||||
|
||||
Response res2;
|
||||
if (!detail::process_socket(
|
||||
true, sock, 1, read_timeout_sec_, read_timeout_usec_,
|
||||
[&](Stream &strm, bool /*last_connection*/,
|
||||
bool &connection_close) {
|
||||
Request req2;
|
||||
req2.method = "CONNECT";
|
||||
req2.path = host_and_port_;
|
||||
req2.headers.insert(make_digest_authentication_header(
|
||||
req2, auth, 1, random_string(10),
|
||||
proxy_digest_auth_username_,
|
||||
proxy_digest_auth_password_, true));
|
||||
return process_request(strm, req2, res2, false,
|
||||
connection_close);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = res2;
|
||||
return true;
|
||||
}
|
||||
|
||||
Request new_req;
|
||||
new_req.method = req.method;
|
||||
new_req.path = req.path;
|
||||
new_req.headers = req.headers;
|
||||
new_req.body = req.body;
|
||||
new_req.response_handler = req.response_handler;
|
||||
new_req.content_receiver = req.content_receiver;
|
||||
new_req.progress = req.progress;
|
||||
|
||||
new_req.headers.insert(header);
|
||||
|
||||
Response new_res;
|
||||
auto ret = send(new_req, new_res);
|
||||
if (ret) { res = new_res; }
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
if (!process_and_close_socket(
|
||||
sock, 1,
|
||||
[&](Stream &strm, bool last_connection, bool &connection_close) {
|
||||
if (!is_ssl() && !proxy_host_.empty()) {
|
||||
auto req2 = req;
|
||||
req2.path = "http://" + host_and_port_ + req.path;
|
||||
return process_request(strm, req2, res, last_connection,
|
||||
connection_close);
|
||||
}
|
||||
return process_request(strm, req, res, last_connection,
|
||||
connection_close);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (300 < res.status && res.status < 400 && follow_location_) {
|
||||
return redirect(req, res);
|
||||
}
|
||||
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
if (res.status == 401 || res.status == 407) {
|
||||
auto is_proxy = res.status == 407;
|
||||
const auto &username =
|
||||
is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
|
||||
const auto &password =
|
||||
is_proxy ? proxy_digest_auth_password_ : digest_auth_password_;
|
||||
|
||||
if (!username.empty() && !password.empty()) {
|
||||
std::map<std::string, std::string> auth;
|
||||
if (parse_www_authenticate(res, auth, is_proxy)) {
|
||||
Request new_req = req;
|
||||
auto key = is_proxy ? "Proxy-Authorization" : "WWW-Authorization";
|
||||
new_req.headers.erase(key);
|
||||
new_req.headers.insert(make_digest_authentication_header(
|
||||
req, auth, 1, random_string(10), username, password, is_proxy));
|
||||
|
||||
Response new_res;
|
||||
|
||||
auto ret = send(new_req, new_res);
|
||||
if (ret) { res = new_res; }
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Client::send(const std::vector<Request> &requests,
|
||||
@@ -3493,28 +3649,30 @@ inline bool Client::redirect(const Request &req, Response &res) {
|
||||
std::smatch m;
|
||||
if (!regex_match(location, m, re)) { return false; }
|
||||
|
||||
auto scheme = is_ssl() ? "https" : "http";
|
||||
|
||||
auto next_scheme = m[1].str();
|
||||
auto next_host = m[2].str();
|
||||
auto next_path = m[3].str();
|
||||
if (next_scheme.empty()) { next_scheme = scheme; }
|
||||
if (next_scheme.empty()) { next_scheme = scheme; }
|
||||
if (next_host.empty()) { next_host = host_; }
|
||||
if (next_path.empty()) { next_path = "/"; }
|
||||
|
||||
auto scheme = is_ssl() ? "https" : "http";
|
||||
|
||||
if (next_scheme == scheme && next_host == host_) {
|
||||
return detail::redirect(*this, req, res, next_path);
|
||||
} else {
|
||||
if (next_scheme == "https") {
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
SSLClient cli(next_host.c_str());
|
||||
cli.set_follow_location(true);
|
||||
cli.copy_settings(*this);
|
||||
return detail::redirect(cli, req, res, next_path);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
Client cli(next_host.c_str());
|
||||
cli.set_follow_location(true);
|
||||
cli.copy_settings(*this);
|
||||
return detail::redirect(cli, req, res, next_path);
|
||||
}
|
||||
}
|
||||
@@ -3525,13 +3683,7 @@ inline bool Client::write_request(Stream &strm, const Request &req,
|
||||
BufferStream bstrm;
|
||||
|
||||
// Request line
|
||||
const static std::regex re(
|
||||
R"(^([^:/?#]+://[^/?#]*)?([^?#]*(?:\?[^#]*)?(?:#.*)?))");
|
||||
|
||||
std::smatch m;
|
||||
if (!regex_match(req.path, m, re)) { return false; }
|
||||
|
||||
auto path = m[1].str() + detail::encode_url(m[2].str());
|
||||
const auto &path = detail::encode_url(req.path);
|
||||
|
||||
bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
|
||||
|
||||
@@ -3558,7 +3710,7 @@ inline bool Client::write_request(Stream &strm, const Request &req,
|
||||
if (!req.has_header("Accept")) { headers.emplace("Accept", "*/*"); }
|
||||
|
||||
if (!req.has_header("User-Agent")) {
|
||||
headers.emplace("User-Agent", "cpp-httplib/0.2");
|
||||
headers.emplace("User-Agent", "cpp-httplib/0.5");
|
||||
}
|
||||
|
||||
if (req.body.empty()) {
|
||||
@@ -3579,6 +3731,17 @@ inline bool Client::write_request(Stream &strm, const Request &req,
|
||||
}
|
||||
}
|
||||
|
||||
if (!basic_auth_username_.empty() && !basic_auth_password_.empty()) {
|
||||
headers.insert(make_basic_authentication_header(
|
||||
basic_auth_username_, basic_auth_password_, false));
|
||||
}
|
||||
|
||||
if (!proxy_basic_auth_username_.empty() &&
|
||||
!proxy_basic_auth_password_.empty()) {
|
||||
headers.insert(make_basic_authentication_header(
|
||||
proxy_basic_auth_username_, proxy_basic_auth_password_, true));
|
||||
}
|
||||
|
||||
detail::write_headers(bstrm, req, headers);
|
||||
|
||||
// Flush buffer
|
||||
@@ -3671,7 +3834,7 @@ inline bool Client::process_request(Stream &strm, const Request &req,
|
||||
}
|
||||
|
||||
// Body
|
||||
if (req.method != "HEAD") {
|
||||
if (req.method != "HEAD" && req.method != "CONNECT") {
|
||||
ContentReceiver out = [&](const char *buf, size_t n) {
|
||||
if (res.body.size() + n > res.body.max_size()) { return false; }
|
||||
res.body.append(buf, n);
|
||||
@@ -3691,6 +3854,9 @@ inline bool Client::process_request(Stream &strm, const Request &req,
|
||||
}
|
||||
}
|
||||
|
||||
// Log
|
||||
if (logger_) { logger_(req, res); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3708,8 +3874,7 @@ inline bool Client::process_and_close_socket(
|
||||
inline bool Client::is_ssl() const { return false; }
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path) {
|
||||
Progress dummy;
|
||||
return Get(path, Headers(), dummy);
|
||||
return Get(path, Headers(), Progress());
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
@@ -3719,8 +3884,7 @@ inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
const Headers &headers) {
|
||||
Progress dummy;
|
||||
return Get(path, headers, dummy);
|
||||
return Get(path, headers, Progress());
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response>
|
||||
@@ -3737,37 +3901,36 @@ Client::Get(const char *path, const Headers &headers, Progress progress) {
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
ContentReceiver content_receiver) {
|
||||
Progress dummy;
|
||||
return Get(path, Headers(), nullptr, std::move(content_receiver), dummy);
|
||||
return Get(path, Headers(), nullptr, std::move(content_receiver), Progress());
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress) {
|
||||
return Get(path, Headers(), nullptr, std::move(content_receiver), progress);
|
||||
return Get(path, Headers(), nullptr, std::move(content_receiver),
|
||||
std::move(progress));
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
const Headers &headers,
|
||||
ContentReceiver content_receiver) {
|
||||
Progress dummy;
|
||||
return Get(path, headers, nullptr, std::move(content_receiver), dummy);
|
||||
return Get(path, headers, nullptr, std::move(content_receiver), Progress());
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
const Headers &headers,
|
||||
ContentReceiver content_receiver,
|
||||
Progress progress) {
|
||||
return Get(path, headers, nullptr, std::move(content_receiver), progress);
|
||||
return Get(path, headers, nullptr, std::move(content_receiver),
|
||||
std::move(progress));
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
const Headers &headers,
|
||||
ResponseHandler response_handler,
|
||||
ContentReceiver content_receiver) {
|
||||
Progress dummy;
|
||||
return Get(path, headers, std::move(response_handler), content_receiver,
|
||||
dummy);
|
||||
Progress());
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Response> Client::Get(const char *path,
|
||||
@@ -3988,8 +4151,8 @@ inline std::shared_ptr<Response> Client::Options(const char *path,
|
||||
return send(req, *res) ? res : nullptr;
|
||||
}
|
||||
|
||||
inline void Client::set_keep_alive_max_count(size_t count) {
|
||||
keep_alive_max_count_ = count;
|
||||
inline void Client::set_timeout_sec(time_t timeout_sec) {
|
||||
timeout_sec_ = timeout_sec;
|
||||
}
|
||||
|
||||
inline void Client::set_read_timeout(time_t sec, time_t usec) {
|
||||
@@ -3997,9 +4160,19 @@ inline void Client::set_read_timeout(time_t sec, time_t usec) {
|
||||
read_timeout_usec_ = usec;
|
||||
}
|
||||
|
||||
inline void Client::set_auth(const char *username, const char *password) {
|
||||
username_ = username;
|
||||
password_ = password;
|
||||
inline void Client::set_keep_alive_max_count(size_t count) {
|
||||
keep_alive_max_count_ = count;
|
||||
}
|
||||
|
||||
inline void Client::set_basic_auth(const char *username, const char *password) {
|
||||
basic_auth_username_ = username;
|
||||
basic_auth_password_ = password;
|
||||
}
|
||||
|
||||
inline void Client::set_digest_auth(const char *username,
|
||||
const char *password) {
|
||||
digest_auth_username_ = username;
|
||||
digest_auth_password_ = password;
|
||||
}
|
||||
|
||||
inline void Client::set_follow_location(bool on) { follow_location_ = on; }
|
||||
@@ -4008,6 +4181,25 @@ inline void Client::set_compress(bool on) { compress_ = on; }
|
||||
|
||||
inline void Client::set_interface(const char *intf) { interface_ = intf; }
|
||||
|
||||
inline void Client::set_proxy(const char *host, int port) {
|
||||
proxy_host_ = host;
|
||||
proxy_port_ = port;
|
||||
}
|
||||
|
||||
inline void Client::set_proxy_basic_auth(const char *username,
|
||||
const char *password) {
|
||||
proxy_basic_auth_username_ = username;
|
||||
proxy_basic_auth_password_ = password;
|
||||
}
|
||||
|
||||
inline void Client::set_proxy_digest_auth(const char *username,
|
||||
const char *password) {
|
||||
proxy_digest_auth_username_ = username;
|
||||
proxy_digest_auth_password_ = password;
|
||||
}
|
||||
|
||||
inline void Client::set_logger(Logger logger) { logger_ = std::move(logger); }
|
||||
|
||||
/*
|
||||
* SSL Implementation
|
||||
*/
|
||||
@@ -4227,21 +4419,21 @@ inline bool SSLServer::process_and_close_socket(socket_t sock) {
|
||||
}
|
||||
|
||||
// SSL HTTP client implementation
|
||||
inline SSLClient::SSLClient(const char *host, int port, time_t timeout_sec,
|
||||
const char *client_cert_path,
|
||||
const char *client_key_path)
|
||||
: Client(host, port, timeout_sec) {
|
||||
inline SSLClient::SSLClient(const std::string &host, int port,
|
||||
const std::string &client_cert_path,
|
||||
const std::string &client_key_path)
|
||||
: Client(host, port, client_cert_path, client_key_path) {
|
||||
ctx_ = SSL_CTX_new(SSLv23_client_method());
|
||||
|
||||
detail::split(&host_[0], &host_[host_.size()], '.',
|
||||
[&](const char *b, const char *e) {
|
||||
host_components_.emplace_back(std::string(b, e));
|
||||
});
|
||||
if (client_cert_path && client_key_path) {
|
||||
if (SSL_CTX_use_certificate_file(ctx_, client_cert_path,
|
||||
if (!client_cert_path.empty() && !client_key_path.empty()) {
|
||||
if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(),
|
||||
SSL_FILETYPE_PEM) != 1 ||
|
||||
SSL_CTX_use_PrivateKey_file(ctx_, client_key_path, SSL_FILETYPE_PEM) !=
|
||||
1) {
|
||||
SSL_CTX_use_PrivateKey_file(ctx_, client_key_path.c_str(),
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
SSL_CTX_free(ctx_);
|
||||
ctx_ = nullptr;
|
||||
}
|
||||
|
||||
+7
-1
@@ -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
|
||||
|
||||
+88
-35
@@ -204,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");
|
||||
@@ -227,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 =
|
||||
@@ -255,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(
|
||||
@@ -287,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;
|
||||
@@ -347,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);
|
||||
@@ -363,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);
|
||||
@@ -379,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);
|
||||
@@ -395,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);
|
||||
@@ -413,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;
|
||||
@@ -474,13 +474,27 @@ TEST(BaseAuthTest, FromHTTPWatch) {
|
||||
}
|
||||
|
||||
{
|
||||
cli.set_auth("hello", "world");
|
||||
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
|
||||
@@ -504,7 +518,7 @@ TEST(DigestAuthTest, FromHTTPWatch) {
|
||||
"/digest-auth/auth-int/hello/world/MD5",
|
||||
};
|
||||
|
||||
cli.set_auth("hello", "world");
|
||||
cli.set_digest_auth("hello", "world");
|
||||
for (auto path : paths) {
|
||||
auto res = cli.Get(path.c_str());
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
@@ -512,6 +526,20 @@ TEST(DigestAuthTest, FromHTTPWatch) {
|
||||
"{\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
|
||||
@@ -619,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) {
|
||||
@@ -876,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) {
|
||||
@@ -1127,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"));
|
||||
}
|
||||
@@ -1646,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";
|
||||
@@ -1658,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);
|
||||
|
||||
@@ -2090,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);
|
||||
|
||||
@@ -2109,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();
|
||||
@@ -2130,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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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"]
|
||||
@@ -0,0 +1 @@
|
||||
hello:$apr1$O6S28OBL$8dr3ixl4Mohf97hgsYvLy/
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
hello:world
|
||||
@@ -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
|
||||
@@ -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
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
docker-compose down --rmi all
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
docker-compose up -d
|
||||
@@ -0,0 +1 @@
|
||||
abcde
|
||||
Reference in New Issue
Block a user