Merge tag '0.8.3'
This commit is contained in:
commit
f9320ae8cb
@ -12,6 +12,8 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
TARGET_LINK_LIBRARIES(${BII_BLOCK_TARGET} INTERFACE rt)
|
||||
ENDIF(CMAKE_SYSTEM_NAME)
|
||||
|
||||
TARGET_LINK_LIBRARIES(${BII_BLOCK_TARGET} INTERFACE curl)
|
||||
|
||||
ENABLE_STYLE_WARNINGS()
|
||||
|
||||
# You can safely delete lines from here...
|
||||
|
@ -9,7 +9,7 @@
|
||||
messmer/spdlog: 1
|
||||
|
||||
[parent]
|
||||
messmer/cpp-utils: 6
|
||||
messmer/cpp-utils: 7
|
||||
[paths]
|
||||
# Local directories to look for headers (within block)
|
||||
# /
|
||||
|
50
network/CurlHttpClient.cpp
Normal file
50
network/CurlHttpClient.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
// Base version taken from https://techoverflow.net/blog/2013/03/15/c-simple-http-download-using-libcurl-easy-api/
|
||||
|
||||
#include "CurlHttpClient.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <curl/curl.h>
|
||||
#include <curl/easy.h>
|
||||
|
||||
using boost::none;
|
||||
using boost::optional;
|
||||
using std::string;
|
||||
using std::ostringstream;
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
size_t CurlHttpClient::write_data(void *ptr, size_t size, size_t nmemb, ostringstream *stream) {
|
||||
stream->write((const char *) ptr, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
CurlHttpClient::CurlHttpClient() {
|
||||
curl = curl_easy_init();
|
||||
}
|
||||
|
||||
CurlHttpClient::~CurlHttpClient() {
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
optional <string> CurlHttpClient::get(const string &url, optional<long> timeoutMsec) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
// example.com is redirected, so we tell libcurl to follow redirection
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); //Prevent "longjmp causes uninitialized stack frame" bug
|
||||
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "deflate");
|
||||
ostringstream out;
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlHttpClient::write_data);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &out);
|
||||
if (timeoutMsec != none) {
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, *timeoutMsec);
|
||||
}
|
||||
// Perform the request, res will get the return code
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
// Check for errors
|
||||
if (res != CURLE_OK) {
|
||||
return none;
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
}
|
28
network/CurlHttpClient.h
Normal file
28
network/CurlHttpClient.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_NETWORK_HTTPCLIENT_HPP
|
||||
#define MESSMER_CPPUTILS_NETWORK_HTTPCLIENT_HPP
|
||||
|
||||
#include "HttpClient.h"
|
||||
#include "../macros.h"
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
class CurlHttpClient final : public HttpClient {
|
||||
public:
|
||||
CurlHttpClient();
|
||||
|
||||
~CurlHttpClient();
|
||||
|
||||
boost::optional <std::string> get(const std::string &url, boost::optional<long> timeoutMsec = boost::none) override;
|
||||
|
||||
private:
|
||||
void *curl;
|
||||
|
||||
static size_t write_data(void *ptr, size_t size, size_t nmemb, std::ostringstream *stream);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CurlHttpClient);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
23
network/FakeHttpClient.cpp
Normal file
23
network/FakeHttpClient.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "FakeHttpClient.h"
|
||||
|
||||
using std::string;
|
||||
using boost::optional;
|
||||
using boost::none;
|
||||
|
||||
namespace cpputils {
|
||||
FakeHttpClient::FakeHttpClient(): _sites() {
|
||||
}
|
||||
|
||||
void FakeHttpClient::addWebsite(const string &url, const string &content) {
|
||||
_sites[url] = content;
|
||||
}
|
||||
|
||||
optional<string> FakeHttpClient::get(const string &url, optional<long> timeoutMsec) {
|
||||
UNUSED(timeoutMsec);
|
||||
auto found = _sites.find(url);
|
||||
if (found == _sites.end()) {
|
||||
return none;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
}
|
26
network/FakeHttpClient.h
Normal file
26
network/FakeHttpClient.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef MESSMER_CPPUTILS_NETWORK_FAKEHTTPCLIENT_H
|
||||
#define MESSMER_CPPUTILS_NETWORK_FAKEHTTPCLIENT_H
|
||||
|
||||
#include "HttpClient.h"
|
||||
#include "../macros.h"
|
||||
#include <map>
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
class FakeHttpClient final : public HttpClient {
|
||||
public:
|
||||
FakeHttpClient();
|
||||
|
||||
void addWebsite(const std::string &url, const std::string &content);
|
||||
|
||||
boost::optional<std::string> get(const std::string &url, boost::optional<long> timeoutMsec = boost::none) override;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> _sites;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FakeHttpClient);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
1
network/HttpClient.cpp
Normal file
1
network/HttpClient.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "HttpClient.h"
|
16
network/HttpClient.h
Normal file
16
network/HttpClient.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef MESSMER_CPPUTILS_NETWORK_HTTPCLIENT_H
|
||||
#define MESSMER_CPPUTILS_NETWORK_HTTPCLIENT_H
|
||||
|
||||
#include <string>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace cpputils {
|
||||
class HttpClient {
|
||||
public:
|
||||
virtual ~HttpClient() {}
|
||||
|
||||
virtual boost::optional<std::string> get(const std::string& url, boost::optional<long> timeoutMsec = boost::none) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
18
pointer/gcc_4_8_compatibility.h
Normal file
18
pointer/gcc_4_8_compatibility.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#ifndef MESSMER_CPPUTILS_GCC48COMPATIBILITY_H
|
||||
#define MESSMER_CPPUTILS_GCC48COMPATIBILITY_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#if __GNUC__ == 4 && __GNUC_MINOR__ == 8
|
||||
// Add std::make_unique
|
||||
namespace std {
|
||||
template<typename T, typename... Args>
|
||||
inline unique_ptr<T> make_unique(Args&&... args) {
|
||||
return unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -5,6 +5,7 @@
|
||||
#include <memory>
|
||||
#include <boost/optional.hpp>
|
||||
#include "../macros.h"
|
||||
#include "gcc_4_8_compatibility.h"
|
||||
#include "cast.h"
|
||||
|
||||
namespace cpputils {
|
||||
|
32
test/network/CurlHttpClientTest.cpp
Normal file
32
test/network/CurlHttpClientTest.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include <google/gtest/gtest.h>
|
||||
#include <google/gmock/gmock.h>
|
||||
#include "../../network/CurlHttpClient.h"
|
||||
#include "../../pointer/unique_ref_boost_optional_gtest_workaround.h"
|
||||
|
||||
using std::string;
|
||||
using boost::none;
|
||||
using testing::MatchesRegex;
|
||||
|
||||
using namespace cpputils;
|
||||
|
||||
TEST(CurlHttpClientTest, InvalidProtocol) {
|
||||
EXPECT_EQ(none, CurlHttpClient().get("invalid://example.com"));
|
||||
}
|
||||
|
||||
TEST(CurlHttpClientTest, InvalidTld) {
|
||||
EXPECT_EQ(none, CurlHttpClient().get("http://example.invalidtld"));
|
||||
}
|
||||
|
||||
TEST(CurlHttpClientTest, InvalidDomain) {
|
||||
EXPECT_EQ(none, CurlHttpClient().get("http://this_is_a_not_existing_domain.com"));
|
||||
}
|
||||
|
||||
TEST(CurlHttpClientTest, ValidHttp) {
|
||||
string content = CurlHttpClient().get("http://example.com").value();
|
||||
EXPECT_THAT(content, MatchesRegex(".*Example Domain.*"));
|
||||
}
|
||||
|
||||
TEST(CurlHttpClientTest, ValidHttps) {
|
||||
string content = CurlHttpClient().get("https://example.com").value();
|
||||
EXPECT_THAT(content, MatchesRegex(".*Example Domain.*"));
|
||||
}
|
39
test/network/FakeHttpClientTest.cpp
Normal file
39
test/network/FakeHttpClientTest.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include <google/gtest/gtest.h>
|
||||
#include "../../network/FakeHttpClient.h"
|
||||
#include "../../pointer/unique_ref_boost_optional_gtest_workaround.h"
|
||||
|
||||
using boost::none;
|
||||
|
||||
using namespace cpputils;
|
||||
|
||||
TEST(FakeHttpClientTest, Empty) {
|
||||
EXPECT_EQ(none, FakeHttpClient().get("http://example.com"));
|
||||
}
|
||||
|
||||
TEST(FakeHttpClientTest, Nonexisting) {
|
||||
FakeHttpClient client;
|
||||
client.addWebsite("http://existing.com", "content");
|
||||
EXPECT_EQ(none, client.get("http://notexisting.com"));
|
||||
}
|
||||
|
||||
TEST(FakeHttpClientTest, Existing) {
|
||||
FakeHttpClient client;
|
||||
client.addWebsite("http://existing.com", "content");
|
||||
EXPECT_EQ("content", client.get("http://existing.com").value());
|
||||
}
|
||||
|
||||
TEST(FakeHttpClientTest, TwoExisting) {
|
||||
FakeHttpClient client;
|
||||
client.addWebsite("http://firstexisting.com", "first_content");
|
||||
client.addWebsite("http://secondexisting.com", "second_content");
|
||||
EXPECT_EQ("first_content", client.get("http://firstexisting.com").value());
|
||||
EXPECT_EQ("second_content", client.get("http://secondexisting.com").value());
|
||||
EXPECT_EQ(none, client.get("http://notexisting.com"));
|
||||
}
|
||||
|
||||
TEST(FakeHttpClientTest, Overwriting) {
|
||||
FakeHttpClient client;
|
||||
client.addWebsite("http://existing.com", "content");
|
||||
client.addWebsite("http://existing.com", "new_content");
|
||||
EXPECT_EQ("new_content", client.get("http://existing.com").value());
|
||||
}
|
Loading…
Reference in New Issue
Block a user