Skip to content

Commit

Permalink
Merge pull request puppetlabs-toy-chest#41 from Magisus/curl-wrapper
Browse files Browse the repository at this point in the history
(LTH-14) Extract facter's curl wrapper to Leatherman
  • Loading branch information
Michael Smith committed Jul 10, 2015
2 parents 668d5c4 + 3e57a42 commit 9923583
Show file tree
Hide file tree
Showing 11 changed files with 1,066 additions and 4 deletions.
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ compile_commands.json
/debug*/
/release*/
/.idea/
/build/
/linux-build/
/dynamic_library/tests/fixtures.hpp
/*build/
/dynamic_library/tests/fixtures.hpp
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ add_leatherman_dir(rapidjson)
add_leatherman_dir(json_container)
add_leatherman_dir(util)
add_leatherman_dir(file_util)
add_leatherman_dir(curl)
if(WIN32)
add_leatherman_dir(windows)
endif()
Expand Down
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,27 @@ To use JsonContainer, you must enable [RapidJSON][2] that is included
as a leatherman component.
Please refer to the [JsonContainer documentation][3] for API details.

### Using curl

To use the curl wrapper library, libcurl must be installed.

On Ubuntu use the following:

apt-get install libcurl4-openssl-dev

On Windows, in Powershell, use:

(New-Object net.webclient).DownloadFile("http://curl.haxx.se/download/curl-7.42.1.zip", "C:\tools\curl-7.42.1.zip")
& 7za x "curl-7.42.1.zip" | FIND /V "ing "
cd curl-7.42.1
mkdir -Path C:\tools\curl-7.42.1-x86_64_mingw-w64_4.8.4_win32_seh\include
cp -r include\curl C:\tools\curl-7.42.1-x86_64_mingw-w64_4.8.4_win32_seh\include
mkdir -Path C:\tools\curl-7.42.1-x86_64_mingw-w64_4.8.4_win32_seh\lib
cp lib\libcurl.a C:\tools\curl-7.42.1-x86_64_mingw-w64_4.8.4_win32_seh\lib

On Windows CMake must also be manually pointed to the correct directory by passing the argument
`-DCMAKE_PREFIX_PATH="C:\tools\curl-7.42.1-x86_64_mingw-w64_4.8.4_win32_seh`.

## Extending Leatherman

Adding a new library to leatherman is easy!
Expand Down
5 changes: 4 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ install:
- ps: wget 'https://s3.amazonaws.com/kylo-pl-bucket/boost_1_57_0-x86_64_mingw-w64_4.8.3_win32_seh.7z' -OutFile "$pwd\boost.7z"
- ps: 7z.exe x boost.7z -oC:\tools | FIND /V "ing "

- ps: wget 'https://s3.amazonaws.com/kylo-pl-bucket/curl-7.42.1-x86_64_mingw-w64_4.8.3_win32_seh.7z' -OutFile "$pwd\curl-7.42.1-x86_64_mingw-w64_4.8.3_win32_seh.7z"
- ps: 7z.exe x "curl-7.42.1-x86_64_mingw-w64_4.8.3_win32_seh.7z" -oC:\tools | FIND /V "ing "

build_script:
- ps: mv "C:\Program Files (x86)\Git\bin\sh.exe" "C:\Program Files (x86)\Git\bin\shxx.exe"
- ps: cmake -G "MinGW Makefiles" -DBOOST_ROOT="C:\tools\boost_1_57_0-x86_64_mingw-w64_4.8.3_win32_seh" -DBOOST_STATIC=ON -DBOOST_NOWIDE_SKIP_TESTS=ON .
- ps: cmake -G "MinGW Makefiles" -DBOOST_ROOT="C:\tools\boost_1_57_0-x86_64_mingw-w64_4.8.3_win32_seh" -DBOOST_STATIC=ON -DBOOST_NOWIDE_SKIP_TESTS=ON -DCMAKE_PREFIX_PATH="C:\tools\curl-7.42.1-x86_64_mingw-w64_4.8.3_win32_seh" .
- ps: mv "C:\Program Files (x86)\Git\bin\shxx.exe" "C:\Program Files (x86)\Git\bin\sh.exe"
- ps: mingw32-make

Expand Down
16 changes: 16 additions & 0 deletions curl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
find_package(CURL REQUIRED)

add_leatherman_includes("${CURL_INCLUDE_DIRS}")

leatherman_dependency(logging)
leatherman_dependency(util)

if (BUILDING_LEATHERMAN)
leatherman_logging_namespace("leatherman.curl")
leatherman_logging_line_numbers()
endif()

add_leatherman_library(src/client.cc src/request.cc src/response.cc)
add_leatherman_headers(inc/leatherman)

target_link_libraries(leatherman_curl "${CURL_LIBRARIES}")
217 changes: 217 additions & 0 deletions curl/inc/leatherman/curl/client.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/**
* @file
* Declares the HTTP client.
*/
#pragma once

#include <leatherman/util/scoped_resource.hpp>
#include "request.hpp"
#include "response.hpp"
#include <curl/curl.h>


namespace leatherman { namespace curl {

/**
* Resource for a cURL handle.
*/
struct curl_handle : util::scoped_resource<CURL*>
{
/**
* Constructs a cURL handle.
*/
curl_handle();

private:
static void cleanup(CURL* curl);
};

/**
* Resource for a cURL linked-list.
*/
struct curl_list : util::scoped_resource<curl_slist*>
{
/**
* Constructs a curl_list.
*/
curl_list();

/**
* Appends the given string onto the list.
* @param value The string to append onto the list.
*/
void append(std::string const& value);

private:
static void cleanup(curl_slist* list);
};

/**
* Resource for a cURL escaped string.
*/
struct curl_escaped_string : util::scoped_resource<char const*>
{
/**
* Constructs a cURL escaped string.
* @param handle The cURL handle to use to perform the escape.
* @param str The string to escape.
*/
curl_escaped_string(curl_handle const& handle, std::string const& str);

private:
static void cleanup(char const* str);
};

/**
* The exception for HTTP.
*/
struct http_exception : std::runtime_error
{
/**
* Constructs an http_exception.
* @param message The exception message.
*/
http_exception(std::string const& message) :
runtime_error(message)
{
}
};

/**
* The exception for HTTP requests.
*/
struct http_request_exception : http_exception
{
/**
* Constructs an http_request_exception.
* @param req The HTTP request that caused the exception.
* @param message The exception message.
*/
http_request_exception(request req, std::string const &message) :
http_exception(message),
_req(std::move(req))
{
}

/**
* Gets the request associated with the exception
* @return Returns the request associated with the exception.
*/
request const& req() const
{
return _req;
}

private:
request _req;
};

/**
* Implements a client for HTTP.
* Note: this class is not thread-safe.
*/
struct client
{
/**
* Constructs an HTTP client.
*/
client();

/**
* Moves the given client into this client.
* @param other The client to move into this client.
*/
client(client&& other);

/**
* Moves the given client into this client.
* @param other The client to move into this client.
* @return Returns this client.
*/
client& operator=(client&& other);

/**
* Performs a GET with the given request.
* @param req The HTTP request to perform.
* @return Returns the HTTP response.
*/
response get(request const& req);

/**
* Performs a POST with the given request.
* @param req The HTTP request to perform.
* @return Returns the HTTP response.
*/
response post(request const& req);

/**
* Performs a PUT with the given request.
* @param req The HTTP request to perform.
* @return Returns the HTTP response.
*/
response put(request const& req);

/**
* Sets the path to the CA certificate file.
* @param cert_file The path to the CA certificate file.
*/
void set_ca_cert(std::string const& cert_file);

/**
* Set client SSL certificate and key.
* @param client_cert The path to the client's certificate file.
* @param client_key The path to the client's key file.
*/
void set_client_cert(std::string const& client_cert, std::string const& client_key);

private:
client(client const&) = delete;
client& operator=(client const&) = delete;

enum struct http_method
{
get,
put,
post
};

struct context
{
context(request const& req, response& res) :
req(req),
res(res),
read_offset(0)
{
}

request const& req;
response& res;
size_t read_offset;
curl_list request_headers;
std::string response_buffer;
};

std::string _ca_cert;
std::string _client_cert;
std::string _client_key;

response perform(http_method method, request const& req);
void set_method(context& ctx, http_method method);
void set_url(context& ctx);
void set_headers(context& ctx);
void set_cookies(context& ctx);
void set_body(context& ctx);
void set_timeouts(context& ctx);
void set_write_callbacks(context& ctx);
void set_client_info(context &ctx);
void set_ca_info(context& ctx);

static size_t read_body(char* buffer, size_t size, size_t count, void* ptr);
static size_t write_header(char* buffer, size_t size, size_t count, void* ptr);
static size_t write_body(char* buffer, size_t size, size_t count, void* ptr);
static int debug(CURL* handle, curl_infotype type, char* data, size_t size, void* ptr);

curl_handle _handle;
};

}} // namespace leatherman::curl
Loading

0 comments on commit 9923583

Please sign in to comment.