diff --git a/CMakeLists.txt b/CMakeLists.txt index b0ea186..7169400 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,8 +42,8 @@ else() endif() find_package(jsoncpp CONFIG REQUIRED) -find_package(PkgConfig REQUIRED) -pkg_check_modules(curlpp REQUIRED IMPORTED_TARGET curlpp) +# Some distributions do not contain Poco*Config.cmake recipes. +find_package(Poco COMPONENTS Foundation Net NetSSL CONFIG) add_subdirectory(src) diff --git a/README.adoc b/README.adoc index e53b2c4..752c8c1 100644 --- a/README.adoc +++ b/README.adoc @@ -15,7 +15,7 @@ See https://schlomp.space/tastytea/gitea2rss/src/branch/master/gitea2rss.1.adoc[ Add my https://schlomp.space/tastytea/overlay[repository] and install it from there. -[source,shellsession] +[source,shell] ---- eselect repository enable tastytea echo "www-misc/gitea2rss ~amd64" >> /etc/portage/package.accept_keywords/gitea2rss @@ -31,21 +31,16 @@ emerge -a dev-util/gitea2rss * C++ compiler (tested: https://gcc.gnu.org/[gcc] 5/6/7/8, https://llvm.org/[clang] 3/5/6) * https://cmake.org/[cmake] (at least: 3.6) -* https://pkgconfig.freedesktop.org/wiki/[pkgconfig] (tested: 0.29) -* http://www.curlpp.org/[curlpp] (tested: 0.8) +* https://pocoproject.org/[POCO] (tested: 1.9 / 1.7) * https://github.com/open-source-parsers/jsoncpp[jsoncpp] (tested: 1.8) * Optional: ** Manpage: http://asciidoc.org/[asciidoc] (tested: 8.6) ===== Debian stretch -[source,shellsession] +[source,shell] ---- -echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release -echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list -apt-get update -apt-get install build-essential cmake pkg-config libcurl4-openssl-dev libjsoncpp-dev asciidoc -apt-get install -t sid libcurlpp-dev +apt-get install build-essential cmake libpoco-dev libjsoncpp-dev asciidoc ---- ==== Get sourcecode @@ -57,14 +52,14 @@ https://schlomp.space/tastytea/gitea2rss/releases[schlomp.space]. ===== Development version -[source,shellsession] +[source,shell] ---- git clone https://schlomp.space/tastytea/gitea2rss.git ---- ==== Compile -[source,shellsession] +[source,shell] ---- mkdir build cd build/ diff --git a/man/gitea2rss.1.adoc b/man/gitea2rss.1.adoc index 6382192..698bc29 100644 --- a/man/gitea2rss.1.adoc +++ b/man/gitea2rss.1.adoc @@ -2,7 +2,7 @@ :doctype: manpage :Author: tastytea :Email: tastytea@tastytea.de -:Date: 2019-04-22 +:Date: 2019-08-09 :Revision: 0.0.0 :man source: gitea2rss :man version: {revision} @@ -57,8 +57,8 @@ this in it: == PROXY SERVERS -Since gitea2rss is built on libcurl, it respects the same proxy environment -variables. See *curl*(1), section _ENVIRONMENT_. +*gitea2rss* supports HTTP proxies set via the environment variable +_http_proxy_. Accepted formats are _http://host:port/_ or _host:port_. == EXAMPLES @@ -96,7 +96,7 @@ https://git.example.com/user/project` == SEE ALSO -*crontab*(1), *crontab*(5), *curl*(1) +*crontab*(1), *crontab*(5) == REPORTING BUGS diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9a142fa..a4792c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,26 @@ target_include_directories(${PROJECT_NAME} PRIVATE "$") target_link_libraries(${PROJECT_NAME} - PRIVATE PkgConfig::curlpp jsoncpp_lib) + PRIVATE jsoncpp_lib) + +# If no Poco*Config.cmake recipes are found, look for headers in standard dirs. +if(PocoNetSSL_FOUND) + target_link_libraries(${PROJECT_NAME} + PRIVATE Poco::Foundation Poco::Net Poco::NetSSL) +else() + find_file(Poco_h NAMES "Poco/Poco.h" + PATHS "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}") + + if("${Poco_h}" STREQUAL "Poco_h-NOTFOUND") + message(FATAL_ERROR "Could not find POCO.") + else() + message(WARNING + "Your distribution of POCO doesn't contain the *Config.cmake recipes, " + "but the files seem to be in the standard directories. " + "Let's hope this works.") + target_link_libraries(${PROJECT_NAME} + PRIVATE PocoFoundation PocoNet PocoNetSSL) + endif() +endif() install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/gitea2rss.hpp b/src/gitea2rss.hpp index a3b609b..aed98fc 100644 --- a/src/gitea2rss.hpp +++ b/src/gitea2rss.hpp @@ -28,6 +28,9 @@ using std::uint8_t; extern bool cgi; +//! Set proxy from environment variable `http_proxy`. +void set_proxy(); + //! Fetch HTTP document. const string get_http(const string &url); diff --git a/src/http.cpp b/src/http.cpp index c4233cb..a022b5e 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -17,58 +17,142 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "version.hpp" #include "gitea2rss.hpp" -namespace curlopts = curlpp::options; - using std::cout; using std::cerr; using std::endl; -using std::ostringstream; -using std::uint16_t; +using std::istream; +using std::unique_ptr; +using std::make_unique; +using Poco::Net::HTTPClientSession; +using Poco::Net::HTTPSClientSession; +using Poco::Net::HTTPRequest; +using Poco::Net::HTTPResponse; +using Poco::Net::HTTPMessage; +using Poco::StreamCopier; +using Poco::Environment; -const string get_http(const string &url) +void set_proxy() { - string answer; - try { - ostringstream oss; - curlpp::Easy request; + HTTPClientSession::ProxyConfig proxy; + string proxy_env = Environment::get("http_proxy"); + size_t pos; - request.setOpt(string("gitea2rss/") - + global::version); - request.setOpt({ "Connection: close" }); - request.setOpt(true); - request.setOpt(url); - request.setOpt(&oss); - request.perform(); - - uint16_t ret = curlpp::infos::ResponseCode::get(request); - if (ret == 200 || ret == 302 || ret == 307 - || ret == 301 || ret == 308) + // Only keep text between // and /. + if ((pos = proxy_env.find("//")) != string::npos) { - answer = oss.str(); + proxy_env = proxy_env.substr(pos + 2); + } + if ((pos = proxy_env.find('/')) != string::npos) + { + proxy_env = proxy_env.substr(0, pos); + } + + if ((pos = proxy_env.find(':')) != string::npos) + { + proxy.host = proxy_env.substr(0, pos); + proxy.port = std::stoi(proxy_env.substr(pos + 1)); } else + { + proxy.host = proxy_env; + } + + HTTPClientSession::setGlobalProxyConfig(proxy); + } + catch (const std::exception &) + { + // No proxy found, no problem. + } +} + +const string get_http(const string &url) +{ + try + { + Poco::URI poco_uri(url); + string path = poco_uri.getPathAndQuery(); + if (path.empty()) + { + path = "/"; + } + + unique_ptr session; + if (poco_uri.getScheme() == "https") + { + session = make_unique(poco_uri.getHost(), + poco_uri.getPort()); + } + else if (poco_uri.getScheme() == "http") + { + session = make_unique(poco_uri.getHost(), + poco_uri.getPort()); + } + else + { + throw Poco::Exception("Protocol not supported."); + } + + HTTPRequest request(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1); + request.set("User-Agent", string("gitea2rss/") + global::version); + + HTTPResponse response; + + session->sendRequest(request); + istream &rs = session->receiveResponse(response); + + // Not using the constants because some are too new for Debian stretch. + switch (response.getStatus()) + { + case 301: // HTTPResponse::HTTP_MOVED_PERMANENTLY + case 308: // HTTPResponse::HTTP_PERMANENT_REDIRECT + case 302: // HTTPResponse::HTTP_FOUND + case 303: // HTTPResponse::HTTP_SEE_OTHER + case 307: // HTTPResponse::HTTP_TEMPORARY_REDIRECT + { + string location = response.get("Location"); + if (location.substr(0, 4) != "http") + { + location = poco_uri.getScheme() + "://" + poco_uri.getHost() + + location; + } + return get_http(location); + } + case HTTPResponse::HTTP_OK: + { + string answer; + StreamCopier::copyToString(rs, answer); + return answer; + } + default: { if (cgi) { - cout << "Status: " << std::to_string(ret) << endl; + cout << "Status: " << response.getStatus() << endl; } - cerr << "HTTP Error: " << std::to_string(ret) << endl; + cerr << "HTTP Error: " << response.getStatus() << endl; + + return ""; + } } } - catch (const std::exception &e) + catch (const Poco::Exception &e) { - cerr << "Error: " << e.what() << endl; + cerr << "Error: " << e.displayText() << endl; } - return answer; + return ""; } diff --git a/src/main.cpp b/src/main.cpp index f33af21..80e852f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,8 +16,8 @@ #include #include -#include -#include +#include +#include #include "version.hpp" #include "gitea2rss.hpp" @@ -26,20 +26,22 @@ using std::cerr; using std::endl; using std::string; using std::chrono::system_clock; +using Poco::Environment; int main(int argc, char *argv[]) { - const char *envquery = std::getenv("QUERY_STRING"); + const string query = Environment::get("QUERY_STRING"); string url; string type = "releases"; - curlpp::initialize(); + Poco::Net::initializeSSL(); - if (envquery != nullptr) + set_proxy(); + + if (!query.empty()) { - const string query = envquery; - const char *envbaseurl = std::getenv("GITEA2RSS_BASEURL"); - if (envbaseurl == nullptr) + const string baseurl = Environment::get("GITEA2RSS_BASEURL"); + if (baseurl.empty()) { cout << "Status: 500 Internal Server Error\n\n"; cerr << "Error: GITEA2RSS_BASEURL not set\n"; @@ -56,7 +58,7 @@ int main(int argc, char *argv[]) } const size_t pos_repo = pos_found + 5; const size_t pos_endrepo = query.find('&', pos_repo) - pos_repo; - url = string(envbaseurl) + "/" + query.substr(pos_repo, pos_endrepo); + url = string(baseurl) + "/" + query.substr(pos_repo, pos_endrepo); // Look for type in QUERY_STRING. pos_found = query.find("type="); @@ -101,7 +103,7 @@ int main(int argc, char *argv[]) cout << " \n" "\n"; - curlpp::terminate(); + Poco::Net::uninitializeSSL(); return 0; } diff --git a/src/write.cpp b/src/write.cpp index 6baeeaf..541be20 100644 --- a/src/write.cpp +++ b/src/write.cpp @@ -16,11 +16,12 @@ #include #include -#include +#include #include "version.hpp" #include "gitea2rss.hpp" using std::cout; +using Poco::Environment; void write_line(const uint8_t spaces, const string &tag, const string &value) { @@ -43,14 +44,14 @@ void write_line(const uint8_t spaces, const string &tag, const string &value) void write_preamble(const string &url, const string &type) { - const char *request_uri = std::getenv("REQUEST_URI"); - const char *server_name = std::getenv("SERVER_NAME"); - const char *https = getenv("HTTPS"); + const string request_uri = Environment::get("REQUEST_URI"); + const string server_name = Environment::get("SERVER_NAME"); + const string https = Environment::get("HTTPS"); string selfurl; - if (request_uri != nullptr && server_name != nullptr) + if (!request_uri.empty() && !server_name.empty()) { - if (https != nullptr && string(https) == "on") + if (https == "on") { selfurl = "https://"; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2b8737d..6094c72 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,7 @@ target_include_directories(${PROJECT_NAME}_testlib "$") target_link_libraries(${PROJECT_NAME}_testlib - PRIVATE PkgConfig::curlpp jsoncpp_lib) + PRIVATE Poco::Foundation Poco::Net Poco::NetSSL jsoncpp_lib) file(GLOB sources_tests test_*.cpp)