Skip to content

Commit

Permalink
Remove curl form dependencies, resolve #27
Browse files Browse the repository at this point in the history
  • Loading branch information
matken11235 committed Feb 3, 2019
1 parent 0bb4ff3 commit 6b622c0
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 92 deletions.
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME}
"/usr/local/lib/libboost_filesystem-mt.a"
"/usr/local/lib/libboost_system-mt.a"
"curl"
"ssl"
"crypto"
"yaml-cpp")
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ curl -fsSL https://sh.poac.io | bash
Poac requires the following tools and packages to build:
* [`boost`](https://github.com/boostorg): `1.66.0` or higher
* [`cmake`](https://github.com/Kitware/CMake): `3.0` or higher
* [`libcurl`](https://github.com/curl/curl): `7.63.0`
* [`openssl`](https://github.com/openssl/openssl): as new as possible
* [`yaml-cpp`](https://github.com/jbeder/yaml-cpp): `0.6.0` or higher

Expand Down
1 change: 0 additions & 1 deletion docs/en/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ curl -fsSL https://sh.poac.io | bash
Poac requires the following tools and packages to build:
* [`boost`](https://github.com/boostorg): `1.66.0` or higher
* [`cmake`](https://github.com/Kitware/CMake): `3.0` or higher
* [`libcurl`](https://github.com/curl/curl): as new as possible
* [`openssl`](https://github.com/openssl/openssl): as new as possible
* [`yaml-cpp`](https://github.com/jbeder/yaml-cpp): `0.6.0` or higher

Expand Down
1 change: 0 additions & 1 deletion docs/ja/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ curl -fsSL https://sh.poac.io | bash
poac はビルドするために以下のツールとパッケージが必要です:
* [`boost`](https://github.com/boostorg): `1.66.0` もしくはそれ以上
* [`cmake`](https://github.com/Kitware/CMake): `3.0` もしくはそれ以上
* [`libcurl`](https://github.com/curl/curl): `7.63.0` もしくはそれ以上
* [`openssl`](https://github.com/openssl/openssl): できるだけ最新のもの
* [`yaml-cpp`](https://github.com/jbeder/yaml-cpp): `0.6.0` もしくはそれ以上

Expand Down
2 changes: 0 additions & 2 deletions include/poac/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ namespace poac {
static constexpr char const* POAC_TOKENS_VALIDATE_API =
"/api/tokens/validate";

static constexpr char const* POAC_PACKAGE_UPLOAD_API =
"https://poac-pm.appspot.com/packages/upload";
static constexpr char const* POAC_UPLOAD_API_HOST =
"poac-pm.appspot.com";
static constexpr char const* POAC_UPLOAD_API =
Expand Down
157 changes: 81 additions & 76 deletions include/poac/io/network.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
#include <fstream>
#include <string>
#include <string_view>
#include <sstream>
#include <map>
#include <variant>
#include <optional>

#include <curl/curl.h>
#include <boost/filesystem.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
Expand Down Expand Up @@ -144,91 +144,96 @@ namespace poac::io::network {
}


void PostFile( // TODO: WIP
std::string post_file(
const std::string& token,
const std::string& from_file,
std::string_view target="/post",
std::string_view host="httpbin.org")
const boost::filesystem::path& file_path,
std::string_view target=POAC_UPLOAD_API,
std::string_view host=POAC_UPLOAD_API_HOST)
{
auto req = create_request<http::empty_body>(http::verb::post, target, host);
namespace fs = boost::filesystem;

const std::string CRLF = "\r\n";
const std::string boundary = boost::lexical_cast<std::string>(boost::uuids::random_generator{}());
const std::string boundary_footer = CRLF + "--" + boundary + "--" + CRLF; // footer
const std::string content_disposition = "Content-Disposition: form-data; ";

std::stringstream token_stream;
token_stream << "--" << boundary << CRLF
<< content_disposition << "name=\"token\"" << CRLF << CRLF
<< token;

std::stringstream file_stream;
file_stream << CRLF << "--" << boundary << CRLF
<< content_disposition << "name=\"file\"; filename=\"" << file_path.filename().string() << "\"" << CRLF
<< "Content-Type: application/x-gzip" << CRLF
<< "Content-Transfer-Encoding: binary" << CRLF << CRLF;

auto req = create_request<http::string_body>(http::verb::post, target, host);
req.set(http::field::accept, "*/*");
req.set(http::field::content_type, "multipart/form-data; boundary=" + boundary);
const auto content_length = token_stream.str().size() + file_stream.str().size() + fs::file_size(file_path) + boundary_footer.size();
req.set(http::field::content_length, content_length);

const std::string boundary = boost::lexical_cast<std::string>(boost::uuids::random_generator()());
std::string content_disposition =
"form-data; name=\"token\"\r\n"
"\r\n"
+ token + "\r\n"
"--" + boundary + "\r\n"
"Content-Disposition: form-data; name=\"file\"; filename=\"" + from_file + "\"\r\n"
"Content-Type: application/x-gzip\r\n"
"Content-Transfer-Encoding: binary\r\n"
"\r\n";

// std::ifstream file(from_file, std::ios::in | std::ios::binary);
// std::string binary((std::istreambuf_iterator<char>(file)),
// std::istreambuf_iterator<char>());
// content_disposition += binary;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx{ ssl::context::sslv23 };
// These objects perform our I/O
boost::asio::ip::tcp::resolver resolver{ ioc };
ssl::stream<boost::asio::ip::tcp::socket> stream{ ioc, ctx };

// http::request_serializer<http::empty_body> sr{ req }; // TODO: chunked
// sr.
// Set SNI Hostname (many hosts need this to handshake successfully)
if(!SSL_set_tlsext_host_name(stream.native_handle(), std::string(host).c_str()))
{
boost::system::error_code ec{
static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()
};
throw boost::system::system_error{ ec };
}
// Look up the domain name
const auto port = "443";
const auto results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
boost::asio::connect(stream.next_layer(), results.begin(), results.end());
// Perform the SSL handshake
stream.handshake(ssl::stream_base::client);

content_disposition += "\r\n--" + boundary + "--" + "\r\n"; // footer
// Convert request to string
std::stringstream reqss;
reqss << req;
// Send the HTTP request to the remote host
stream.write_some(boost::asio::buffer(reqss.str()));
stream.write_some(boost::asio::buffer(token_stream.str()));
stream.write_some(boost::asio::buffer(file_stream.str()));
// Read file and write to stream
{
std::ifstream file(file_path.string(), std::ios::in | std::ios::binary);
char buf[512];
while (!file.eof()) {
file.read(buf, 512);
stream.write_some(boost::asio::buffer(buf, file.gcount()));
}
}
// Write footer to stream
stream.write_some(boost::asio::buffer(boundary_footer));

req.set(http::field::content_type, "multipart/form-data; boundary=" + boundary);
// "Content-Disposition: " + "\r\n\r\n--" -> 27
const auto content_length = 27 + boundary.length() + content_disposition.length();
req.set(http::field::content_length, std::to_string(content_length) + "\r\n\r\n--" + boundary);
req.set(http::field::content_disposition, content_disposition);

std::cout << req << std::endl;
// const auto res = request<http::string_body>(req, host);
// std::cout << res << std::endl;
}
// This buffer is used for reading and must be persisted
boost::beast::flat_buffer buffer;
// Declare a container to hold the response
http::response<http::string_body> res;
// Receive the HTTP response
http::read(stream, buffer, res);

void post_file(
const std::string& from_file,
const std::string& token)
{
struct curl_httppost* formpost = nullptr;
struct curl_httppost* lastptr = nullptr;
struct curl_slist* headers = nullptr;

curl_global_init(CURL_GLOBAL_ALL);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "token",
CURLFORM_COPYCONTENTS, token.c_str(),
CURLFORM_END);
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_FILE, from_file.c_str(),
CURLFORM_END);
// Fill in the submit field too, even if this is rarely needed
curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "submit",
CURLFORM_COPYCONTENTS, "send",
CURLFORM_END);

if (CURL* curl = curl_easy_init(); curl != nullptr) {
curl_easy_setopt(curl, CURLOPT_URL, POAC_PACKAGE_UPLOAD_API);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

headers = curl_slist_append(headers, "Expect:");
headers = curl_slist_append(headers, "Content-Type: multipart/form-data");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
if (CURLcode res = curl_easy_perform(curl); res != CURLE_OK) {
std::cerr << "curl told us " << res << std::endl;
}
curl_easy_cleanup(curl);
curl_formfree(formpost);
curl_slist_free_all(headers);
// Gracefully close the stream
boost::system::error_code ec;
stream.shutdown(ec);
if (ec == boost::asio::error::eof) {
// Rationale: https://stackoverflow.com/q/25587403
ec.assign(0, ec.category());
}

// TODO: response is written arbitrarily
std::cout << '\b';
std::cout << cli::left(100);
for (int i = 0; i < 100; ++i)
std::cout << ' ';
std::cout << cli::left(100);
return res.body().data();
}


Expand Down
5 changes: 3 additions & 2 deletions include/poac/subcmd/publish.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ namespace poac::subcmd {
if (!fs::exists("poac.yml")) {
throw exception::error("poac.yml does not exists");
}
// FIXME: could not get response
io::network::post_file(output_dir, token);
if (const auto res = io::network::post_file(token, output_dir); res != "ok") {
throw exception::error(res);
}

// Check exists package
io::network::Headers headers;
Expand Down
8 changes: 0 additions & 8 deletions poac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@ deps:
- boost_filesystem
- boost_timer
- boost_chrono
github/curl/curl:
tag: curl-7_61_0
build:
system: cmake
environment:
MAC_RPATH: 1 # TODO: Branch by OS
OPENSSL_ROOT_DIR: /usr/local/opt/openssl/ # TODO: 抽象化
link: static
github/jbeder/yaml-cpp:
tag: yaml-cpp-0.6.2
build: cmake
Expand Down

0 comments on commit 6b622c0

Please sign in to comment.