Added url::Get interface

This commit is contained in:
yhirose 2020-04-21 23:00:39 -04:00
parent 2b7a968468
commit da26b517a3
6 changed files with 153 additions and 6 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@ tags
example/server example/server
example/client example/client
example/hello example/hello
example/simplecli
example/simplesvr example/simplesvr
example/benchmark example/benchmark
example/redirect example/redirect

View File

@ -5,7 +5,7 @@ OPENSSL_DIR = /usr/local/opt/openssl
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
all: server client hello simplesvr upload redirect sse benchmark all: server client hello simplecli simplesvr upload redirect sse benchmark
server : server.cc ../httplib.h Makefile server : server.cc ../httplib.h Makefile
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
@ -16,6 +16,9 @@ client : client.cc ../httplib.h Makefile
hello : hello.cc ../httplib.h Makefile hello : hello.cc ../httplib.h Makefile
$(CXX) -o hello $(CXXFLAGS) hello.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(CXX) -o hello $(CXXFLAGS) hello.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
simplecli : simplecli.cc ../httplib.h Makefile
$(CXX) -o simplecli $(CXXFLAGS) simplecli.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
simplesvr : simplesvr.cc ../httplib.h Makefile simplesvr : simplesvr.cc ../httplib.h Makefile
$(CXX) -o simplesvr $(CXXFLAGS) simplesvr.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(CXX) -o simplesvr $(CXXFLAGS) simplesvr.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
@ -36,4 +39,4 @@ pem:
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem
clean: clean:
rm server client hello simplesvr upload redirect sse benchmark *.pem rm server client hello simplecli simplesvr upload redirect sse benchmark *.pem

View File

@ -15,5 +15,5 @@ int main(void) {
res.set_content("Hello World!", "text/plain"); res.set_content("Hello World!", "text/plain");
}); });
svr.listen("localhost", 1234); svr.listen("localhost", 8080);
} }

33
example/simplecli.cc Normal file
View File

@ -0,0 +1,33 @@
//
// simplecli.cc
//
// Copyright (c) 2019 Yuji Hirose. All rights reserved.
// MIT License
//
#include <httplib.h>
#include <iostream>
#define CA_CERT_FILE "./ca-bundle.crt"
using namespace std;
int main(void) {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
httplib::url::Options options;
options.ca_cert_file_path = CA_CERT_FILE;
// options.server_certificate_verification = true;
auto res = httplib::url::Get("https://localhost:8080/hi", options);
#else
auto res = httplib::url::Get("http://localhost:8080/hi");
#endif
if (res) {
cout << res->status << endl;
cout << res->get_header_value("Content-Type") << endl;
cout << res->body << endl;
}
return 0;
}

View File

@ -3885,10 +3885,10 @@ inline bool Client::redirect(const Request &req, Response &res) {
if (location.empty()) { return false; } if (location.empty()) { return false; }
const static std::regex re( const static std::regex re(
R"(^(?:(https?):)?(?://([^/?#]*)(?:(:\d+))?)?([^?#]*(?:\?[^#]*)?)(?:#.*)?)"); R"(^(?:(https?):)?(?://([^:/?#]*)(?::(\d+))?)?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");
std::smatch m; std::smatch m;
if (!regex_match(location, m, re)) { return false; } if (!std::regex_match(location, m, re)) { return false; }
auto scheme = is_ssl() ? "https" : "http"; auto scheme = is_ssl() ? "https" : "http";
@ -4967,6 +4967,63 @@ inline bool SSLClient::check_host_name(const char *pattern,
} }
#endif #endif
namespace url {
struct Options {
// TODO: support more options...
bool follow_location = false;
std::string client_cert_path;
std::string client_key_path;
std::string ca_cert_file_path;
std::string ca_cert_dir_path;
bool server_certificate_verification = false;
};
inline std::shared_ptr<Response> Get(const char *url, Options &options) {
const static std::regex re(
R"(^(https?)://([^:/?#]+)(?::(\d+))?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");
std::cmatch m;
if (!std::regex_match(url, m, re)) { return nullptr; }
auto next_scheme = m[1].str();
auto next_host = m[2].str();
auto port_str = m[3].str();
auto next_path = m[4].str();
auto next_port = !port_str.empty() ? std::stoi(port_str)
: (next_scheme == "https" ? 443 : 80);
if (next_path.empty()) { next_path = "/"; }
if (next_scheme == "https") {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
SSLClient cli(next_host.c_str(), next_port, options.client_cert_path,
options.client_key_path);
cli.set_follow_location(options.follow_location);
cli.set_ca_cert_path(options.ca_cert_file_path.c_str(), options.ca_cert_dir_path.c_str());
cli.enable_server_certificate_verification(
options.server_certificate_verification);
return cli.Get(next_path.c_str());
#else
return nullptr;
#endif
} else {
Client cli(next_host.c_str(), next_port, options.client_cert_path,
options.client_key_path);
cli.set_follow_location(options.follow_location);
return cli.Get(next_path.c_str());
}
}
inline std::shared_ptr<Response> Get(const char *url) {
Options options;
return Get(url, options);
}
} // namespace url
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
} // namespace httplib } // namespace httplib

View File

@ -654,7 +654,7 @@ TEST(YahooRedirectTestWithURL, Redirect) {
ASSERT_TRUE(res != nullptr); ASSERT_TRUE(res != nullptr);
EXPECT_EQ(301, res->status); EXPECT_EQ(301, res->status);
httplib::url::options options; httplib::url::Options options;
options.follow_location = true; options.follow_location = true;
res = httplib::url::Get("http://yahoo.com", options); res = httplib::url::Get("http://yahoo.com", options);
@ -669,6 +669,59 @@ TEST(HttpsToHttpRedirectTest, Redirect) {
cli.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302"); cli.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
ASSERT_TRUE(res != nullptr); ASSERT_TRUE(res != nullptr);
} }
TEST(HttpsToHttpRedirectTestWithURL, Redirect) {
httplib::url::Options options;
options.follow_location = true;
auto res = httplib::url::Get(
"https://httpbin.org/"
"redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
ASSERT_TRUE(res != nullptr);
}
TEST(RedirectToDifferentPort, Redirect) {
Server svr8080;
Server svr8081;
svr8080.Get("/1", [&](const Request & /*req*/, Response &res) {
res.set_redirect("http://localhost:8081/2");
});
svr8081.Get("/2", [&](const Request & /*req*/, Response &res) {
res.set_content("Hello World!", "text/plain");
});
auto thread8080 = std::thread([&]() {
svr8080.listen("localhost", 8080);
});
auto thread8081 = std::thread([&]() {
svr8081.listen("localhost", 8081);
});
while (!svr8080.is_running() || !svr8081.is_running()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// Give GET time to get a few messages.
std::this_thread::sleep_for(std::chrono::seconds(1));
Client cli("localhost", 8080);
cli.set_follow_location(true);
auto res = cli.Get("/1");
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(200, res->status);
EXPECT_EQ(res->body, "Hello World!");
svr8080.stop();
svr8081.stop();
thread8080.join();
thread8081.join();
ASSERT_FALSE(svr8080.is_running());
ASSERT_FALSE(svr8081.is_running());
}
#endif #endif
TEST(Server, BindAndListenSeparately) { TEST(Server, BindAndListenSeparately) {