Add HttpClient
This commit is contained in:
parent
5148a6571e
commit
feb806b392
@ -12,6 +12,8 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
|||||||
TARGET_LINK_LIBRARIES(${BII_BLOCK_TARGET} INTERFACE rt)
|
TARGET_LINK_LIBRARIES(${BII_BLOCK_TARGET} INTERFACE rt)
|
||||||
ENDIF(CMAKE_SYSTEM_NAME)
|
ENDIF(CMAKE_SYSTEM_NAME)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(${BII_BLOCK_TARGET} INTERFACE curl)
|
||||||
|
|
||||||
ENABLE_STYLE_WARNINGS()
|
ENABLE_STYLE_WARNINGS()
|
||||||
|
|
||||||
# You can safely delete lines from here...
|
# You can safely delete lines from here...
|
||||||
|
47
network/CurlHttpClient.cpp
Normal file
47
network/CurlHttpClient.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// 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) {
|
||||||
|
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);
|
||||||
|
// 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) 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
|
22
network/FakeHttpClient.cpp
Normal file
22
network/FakeHttpClient.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#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) {
|
||||||
|
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) 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) = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
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