diff --git a/build/autotools/m4/lol-conf.m4 b/build/autotools/m4/lol-conf.m4 index 021d693f..ce7729c0 100644 --- a/build/autotools/m4/lol-conf.m4 +++ b/build/autotools/m4/lol-conf.m4 @@ -84,6 +84,15 @@ if test "$ac_cv_have_getopt_long" != "no"; then fi +dnl Use OpenSSL? +ac_cv_have_openssl=no +AC_CHECK_LIB(ssl, OPENSSL_init_ssl, + [ac_cv_have_openssl=yes + AC_DEFINE(LOL_USE_OPENSSL, 1, Define to 1 to use OpenSSL) + LOL_LIBS="${LOL_LIBS} -lssl -lcrypto"]) +AM_CONDITIONAL(LOL_USE_OPENSSL, test "${ac_cv_have_openssl}" = "yes") + + dnl Use Bullet Physics? ac_cv_my_have_bullet="no" if test "${enable_bullet}" != "no"; then diff --git a/doc/tutorial/17_net.cpp b/doc/tutorial/17_net.cpp index 8785d314..477376bc 100644 --- a/doc/tutorial/17_net.cpp +++ b/doc/tutorial/17_net.cpp @@ -30,12 +30,20 @@ public: { entity::tick_game(seconds); - if (client.get_status() == lol::net::http::status::success) + switch (client.get_status()) { - lol::msg::info("Downloaded %d bytes: %s\n", + case lol::net::http::status::success: + lol::msg::info("downloaded %d bytes: %s\n", (int)client.get_result().size(), client.get_result().c_str()); client.reset(); + break; + case lol::net::http::status::error: + lol::msg::info("error downloading %s\n", client.get_url().c_str()); + client.reset(); + break; + default: + break; } } diff --git a/src/lol/net/http.h b/src/lol/net/http.h index 42bf18f0..340a7de7 100644 --- a/src/lol/net/http.h +++ b/src/lol/net/http.h @@ -23,8 +23,6 @@ namespace net namespace http { -class client_impl; - enum class status : uint8_t { ready = 0, @@ -33,6 +31,8 @@ enum class status : uint8_t error = 3, }; +class client_impl; + class client { public: @@ -45,8 +45,9 @@ public: // Reset state void reset(); - // Get status (may be pending) and result + // Get current URL, status (may be pending), and result status get_status() const; + std::string const & get_url() const; std::string const & get_result() const; private: diff --git a/src/net/http.cpp b/src/net/http.cpp index 67be802a..eabe2dd9 100644 --- a/src/net/http.cpp +++ b/src/net/http.cpp @@ -12,12 +12,20 @@ #include +#if LOL_USE_OPENSSL +# define CPPHTTPLIB_OPENSSL_SUPPORT 1 +#endif + #if __EMSCRIPTEN__ # include #else # include #endif +#include +#include +#include + namespace lol { @@ -31,11 +39,26 @@ class client_impl { public: #if __EMSCRIPTEN__ + ~client_impl() + { + emscripten_fetch_close(impl->m_fetch); + } + + void get(std::string const &url) + { + emscripten_fetch_attr_t attr; + emscripten_fetch_attr_init(&attr); + strcpy(attr.requestMethod, "GET"); + attr.userData = impl.get(); + attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY; + attr.onsuccess = client_impl::on_success; + attr.onerror = client_impl::on_failure; + impl->m_fetch = emscripten_fetch(&attr, url.c_str()); + } + static void on_success(emscripten_fetch_t *fetch) { auto *that = (client_impl *)fetch->userData; - msg::info("finished downloading %llu bytes from URL %s.\n", - fetch->numBytes, fetch->url); that->m_result.assign(fetch->data, fetch->numBytes); that->m_status = status::success; } @@ -50,15 +73,59 @@ public: emscripten_fetch_t *m_fetch = nullptr; #else - void get(std::string const& url) + ~client_impl() { + delete m_thread; + } + void get(std::string const& url) + { + // This regex is copied from cpp-httplib + const static std::regex re( + R"(^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*(?:\?[^#]*)?)(?:#.*)?)"); + + std::smatch m; + if (!std::regex_match(url, m, re)) + { + m_status = status::error; + return; + } + + auto scheme = m[1].str(); + auto host = m[2].str(); + auto path = m[3].str(); + +#ifdef CPPHTTPLIB_OPENSSL_SUPPORT + if (scheme == "https") + m_client = std::make_unique(host); + else +#endif + m_client = std::make_shared(host); + m_client->set_follow_location(true); + + m_thread = new lol::thread([this, path](thread *) + { + auto res = m_client->Get(path.c_str()); + if (res && res->status == 200) + { + m_result = std::move(res->body); + m_status = status::success; + } + else + { + msg::error("downloading %s failed, HTTP failure status code: %d.\n", + m_url.c_str(), res ? res->status : -1); + m_status = status::error; + } + }); } - //httplib::Client &client; + lol::thread *m_thread = nullptr; + std::shared_ptr m_client; #endif status m_status; + std::string m_url; std::string m_result; }; @@ -69,30 +136,19 @@ client::client() client::~client() { -#if __EMSCRIPTEN__ - emscripten_fetch_close(impl->m_fetch); -#endif } void client::get(std::string const &url) { impl->m_status = status::pending; -#if __EMSCRIPTEN__ - emscripten_fetch_attr_t attr; - emscripten_fetch_attr_init(&attr); - strcpy(attr.requestMethod, "GET"); - attr.userData = impl.get(); - attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY; - attr.onsuccess = client_impl::on_success; - attr.onerror = client_impl::on_failure; - impl->m_fetch = emscripten_fetch(&attr, url.c_str()); -#else -#endif + impl->m_url = url; + impl->get(url); } void client::reset() { impl->m_status = status::ready; + impl->m_url.assign(""); impl->m_result.assign(""); } @@ -101,6 +157,11 @@ status client::get_status() const return impl->m_status; } +std::string const & client::get_url() const +{ + return impl->m_url; +} + std::string const & client::get_result() const { return impl->m_result;