Skip to content

Commit

Permalink
Added url::Get interface
Browse files Browse the repository at this point in the history
  • Loading branch information
yhirose committed Apr 22, 2020
1 parent 2b7a968 commit da26b51
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ tags
example/server
example/client
example/hello
example/simplecli
example/simplesvr
example/benchmark
example/redirect
Expand Down
7 changes: 5 additions & 2 deletions example/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ OPENSSL_DIR = /usr/local/opt/openssl
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz

all: server client hello simplesvr upload redirect sse benchmark
all: server client hello simplecli simplesvr upload redirect sse benchmark

server : server.cc ../httplib.h Makefile
$(CXX) -o server $(CXXFLAGS) server.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)
Expand All @@ -16,6 +16,9 @@ client : client.cc ../httplib.h Makefile
hello : hello.cc ../httplib.h Makefile
$(CXX) -o hello $(CXXFLAGS) hello.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)

simplecli : simplecli.cc ../httplib.h Makefile
$(CXX) -o simplecli $(CXXFLAGS) simplecli.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)

simplesvr : simplesvr.cc ../httplib.h Makefile
$(CXX) -o simplesvr $(CXXFLAGS) simplesvr.cc $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT)

Expand All @@ -36,4 +39,4 @@ pem:
openssl req -new -key key.pem | openssl x509 -days 3650 -req -signkey key.pem > cert.pem

clean:
rm server client hello simplesvr upload redirect sse benchmark *.pem
rm server client hello simplecli simplesvr upload redirect sse benchmark *.pem
2 changes: 1 addition & 1 deletion example/hello.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ int main(void) {
res.set_content("Hello World!", "text/plain");
});

svr.listen("localhost", 1234);
svr.listen("localhost", 8080);
}
33 changes: 33 additions & 0 deletions example/simplecli.cc
Original file line number Diff line number Diff line change
@@ -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;
}
61 changes: 59 additions & 2 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -3885,10 +3885,10 @@ inline bool Client::redirect(const Request &req, Response &res) {
if (location.empty()) { return false; }

const static std::regex re(
R"(^(?:(https?):)?(?://([^/?#]*)(?:(:\d+))?)?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");
R"(^(?:(https?):)?(?://([^:/?#]*)(?::(\d+))?)?([^?#]*(?:\?[^#]*)?)(?:#.*)?)");

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

Expand Down Expand Up @@ -4967,6 +4967,63 @@ inline bool SSLClient::check_host_name(const char *pattern,
}
#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
Expand Down
55 changes: 54 additions & 1 deletion test/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ TEST(YahooRedirectTestWithURL, Redirect) {
ASSERT_TRUE(res != nullptr);
EXPECT_EQ(301, res->status);

httplib::url::options options;
httplib::url::Options options;
options.follow_location = true;

res = httplib::url::Get("http://yahoo.com", options);
Expand All @@ -669,6 +669,59 @@ TEST(HttpsToHttpRedirectTest, Redirect) {
cli.Get("/redirect-to?url=http%3A%2F%2Fwww.google.com&status_code=302");
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

TEST(Server, BindAndListenSeparately) {
Expand Down

0 comments on commit da26b51

Please sign in to comment.