Skip to content

Commit

Permalink
Proxy support for Keep-Alive requests
Browse files Browse the repository at this point in the history
  • Loading branch information
yhirose committed Jan 3, 2020
1 parent 6c0e021 commit de844e6
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 114 deletions.
208 changes: 112 additions & 96 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,9 @@ class Client {
bool read_response_line(Stream &strm, Response &res);
bool write_request(Stream &strm, const Request &req, bool last_connection);
bool redirect(const Request &req, Response &res);
bool connect(socket_t sock, Response &res, bool &error);
bool handle_request(Stream &strm, const Request &req, Response &res,
bool last_connection, bool &connection_close);

std::shared_ptr<Response> send_with_content_provider(
const char *method, const char *path, const Headers &headers,
Expand Down Expand Up @@ -2750,9 +2753,7 @@ inline Server::Server()
#ifndef _WIN32
signal(SIGPIPE, SIG_IGN);
#endif
new_task_queue = [] {
return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT);
};
new_task_queue = [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); };
}

inline Server::~Server() {}
Expand Down Expand Up @@ -3445,77 +3446,128 @@ inline bool Client::read_response_line(Stream &strm, Response &res) {
}

inline bool Client::send(const Request &req, Response &res) {
if (req.path.empty()) { return false; }

auto sock = create_client_socket();
if (sock == INVALID_SOCKET) { return false; }

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
// 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);
})) {
detail::close_socket(sock);
bool error;
if (!connect(sock, res, error)) { return error; }
}
#endif

return process_and_close_socket(
sock, 1, [&](Stream &strm, bool last_connection, bool &connection_close) {
return handle_request(strm, req, res, last_connection,
connection_close);
});
}

inline bool Client::send(const std::vector<Request> &requests,
std::vector<Response> &responses) {
size_t i = 0;
while (i < requests.size()) {
auto sock = create_client_socket();
if (sock == INVALID_SOCKET) { return false; }

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
if (is_ssl() && !proxy_host_.empty()) {
Response res;
bool error;
if (!connect(sock, res, error)) { return false; }
}
#endif

if (!process_and_close_socket(sock, requests.size() - i,
[&](Stream &strm, bool last_connection,
bool &connection_close) -> bool {
auto &req = requests[i++];
auto res = Response();
auto ret = handle_request(strm, req, res,
last_connection,
connection_close);
if (ret) {
responses.emplace_back(std::move(res));
}
return ret;
})) {
return false;
}
}

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)) {
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);
})) {
detail::close_socket(sock);
return false;
}
return true;
}

inline bool Client::connect(socket_t sock, Response &res, bool &error) {
error = true;
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);
})) {
detail::close_socket(sock);
error = false;
return false;
}

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)) {
Response res3;
if (!detail::process_socket(
true, sock, 1, read_timeout_sec_, read_timeout_usec_,
[&](Stream &strm, bool /*last_connection*/,
bool &connection_close) {
Request req3;
req3.method = "CONNECT";
req3.path = host_and_port_;
req3.headers.insert(make_digest_authentication_header(
req3, auth, 1, random_string(10),
proxy_digest_auth_username_, proxy_digest_auth_password_,
true));
return process_request(strm, req3, res3, false,
connection_close);
})) {
detail::close_socket(sock);
error = false;
return false;
}
} else {
res = res2;
return true;
}
} else {
res = res2;
return false;
}
}
#endif

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;
return true;
}

inline bool Client::handle_request(Stream &strm, const Request &req,
Response &res, bool last_connection,
bool &connection_close) {
if (req.path.empty()) { return false; }

bool ret;

if (!is_ssl() && !proxy_host_.empty()) {
auto req2 = req;
req2.path = "http://" + host_and_port_ + req.path;
ret = process_request(strm, req2, res, last_connection, connection_close);
} else {
ret = process_request(strm, req, res, last_connection, connection_close);
}

if (!ret) { return false; }

if (300 < res.status && res.status < 400 && follow_location_) {
return redirect(req, res);
ret = redirect(req, res);
}

#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
Expand All @@ -3537,50 +3589,14 @@ inline bool Client::send(const Request &req, Response &res) {

Response new_res;

auto ret = send(new_req, new_res);
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,
std::vector<Response> &responses) {
size_t i = 0;
while (i < requests.size()) {
auto sock = create_client_socket();
if (sock == INVALID_SOCKET) { return false; }

if (!process_and_close_socket(
sock, requests.size() - i,
[&](Stream &strm, bool last_connection,
bool &connection_close) -> bool {
auto &req = requests[i];
auto res = Response();
i++;

if (req.path.empty()) { return false; }
auto ret = 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) { responses.emplace_back(std::move(res)); }

return ret;
})) {
return false;
}
}

return true;
return ret;
}

inline bool Client::redirect(const Request &req, Response &res) {
Expand Down
1 change: 0 additions & 1 deletion test/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,6 @@ TEST(DigestAuthTest, FromHTTPWatch) {
"/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",
};

Expand Down
Loading

0 comments on commit de844e6

Please sign in to comment.