Skip to content

Commit

Permalink
use boost instead of libcurl to make http requests
Browse files Browse the repository at this point in the history
  • Loading branch information
npq7721 committed Aug 9, 2024
1 parent 2226bb4 commit a8fcfdb
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 20 deletions.
10 changes: 3 additions & 7 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,9 @@ if test "$use_reduce_exports" = "yes"; then
AX_CHECK_LINK_FLAG([-Wl,--exclude-libs,ALL], [RELDFLAGS="-Wl,--exclude-libs,ALL"], [], [$LDFLAG_WERROR])
fi

AX_CHECK_LINK_FLAG([-lssl], [LDFLAGS="$LDFLAGS -lssl"])
AX_CHECK_LINK_FLAG([-lcrypto], [LDFLAGS="$LDFLAGS -lcrypto"])

if test "$use_tests" = "yes"; then
if test "$HEXDUMP" = ""; then
AC_MSG_ERROR([hexdump is required for tests])
Expand Down Expand Up @@ -1474,13 +1477,6 @@ dnl Check for gmp
AC_CHECK_HEADER([gmp.h])
AC_CHECK_LIB([gmp], [__gmpz_init], [GMP_LIBS=-lgmp], [AC_MSG_ERROR([libgmp missing])])

# Check for libcurl
AC_CHECK_LIB([curl], [curl_easy_init], [have_curl=yes], [have_curl=no])
if test "x$have_curl" = "xyes"; then
AC_DEFINE([HAVE_CURL], [1], [Define to 1 if you have the cURL library.])
LIBS="$LIBS -lcurl"
fi

dnl check for immer header
AC_CHECK_HEADER([immer/map.hpp],, [AC_MSG_ERROR([immer map header not found])])

Expand Down
6 changes: 3 additions & 3 deletions depends/packages/openssl.mk
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package=openssl
$(package)_version=1.1.1n
$(package)_version=1.1.1w
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=40dceb51a4f6a5275bde0e6bf20ef4b91bfc32ed57c0552e2e8e15463372b17a
$(package)_sha256_hash=cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8

define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
Expand Down Expand Up @@ -86,7 +86,7 @@ define $(package)_config_cmds
endef

define $(package)_build_cmds
$(MAKE) -j1 build_crypto libcrypto.pc libssl.pc openssl.pc
$(MAKE) -j4
endef

define $(package)_stage_cmds
Expand Down
2 changes: 1 addition & 1 deletion depends/packages/packages.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
packages:=boost libevent gmp backtrace cmake immer zeromq
packages:=boost libevent gmp backtrace cmake immer zeromq openssl

qrencode_linux_packages = qrencode
qrencode_android_packages = qrencode
Expand Down
1 change: 0 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ LIBBITCOIN_CRYPTO=crypto/libraptoreum_crypto.a
LIBBITCOINQT=qt/libraptoreumqt.a
LIBDASHBLS=dashbls/libdashbls.la
LIBSECP256K1=secp256k1/libsecp256k1.la
LIBBITCOINQT+=-lcurl

if ENABLE_ZMQ
LIBBITCOIN_ZMQ=libraptoreum_zmq.a
Expand Down
4 changes: 2 additions & 2 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ BITCOIN_QT_H = \
qt/sendassetsdialog.h \
qt/sendassetsentry.h \
qt/createassetsdialog.h \
qt/upload_download.h \
qt/uploaddownload.h \
qt/updateassetsdialog.h \
qt/signverifymessagedialog.h \
qt/smartnodelist.h \
Expand Down Expand Up @@ -291,7 +291,7 @@ BITCOIN_QT_WALLET_CPP = \
qt/sendcoinsentry.cpp \
qt/sendassetsdialog.cpp \
qt/createassetsdialog.cpp \
qt/upload_download.cpp \
qt/uploaddownload.cpp \
qt/updateassetsdialog.cpp \
qt/assetsdialog.cpp \
qt/sendassetsentry.cpp \
Expand Down
12 changes: 10 additions & 2 deletions src/qt/assetsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <qt/assetsdialog.h>
#include <qt/forms/ui_assetsdialog.h>
#include <qt/upload_download.h>
//#include <qt/upload_download.h>
#include <qt/uploaddownload.h>
//#include <qt/httpclient.h>

#include <chainparams.h>
#include <qt/clientmodel.h>
Expand Down Expand Up @@ -320,8 +322,14 @@ void AssetsDialog::displayImage(const std::string& cid) {
} else {
ui->referenceLabel->show();
ui->referenceDisplay->show();
// HttpClient httpClient;
// httpClient.sendGetRequest(cid, [this, cid](const QByteArray& data) {
// printf("data size %d\n", data.size());
// });
std::string response_data;
downloadFile(cid, response_data);
//downloadFile(cid, response_data);
download(cid, response_data);
printf("size %ld\n", response_data.size());
QByteArray imageData = QByteArray::fromRawData(response_data.data(), response_data.size());
QBuffer buffer(&imageData);
buffer.open(QIODevice::ReadOnly);
Expand Down
7 changes: 5 additions & 2 deletions src/qt/createassetsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/sendassetsentry.h>
#include <qt/upload_download.h>
//#include <qt/upload_download.h>
#include <qt/uploaddownload.h>

#include <chainparams.h>
#include <interfaces/node.h>
Expand Down Expand Up @@ -795,7 +796,9 @@ void CreateAssetsDialog::CoinControlUpdateLabels() {
}

void CreateAssetsDialog::openFilePicker() {
std::string cid = pickAndSendFileForIpfs(this);
//std::string cid = pickAndSendFileForIpfs(this);
std::string cid;
pickAndUploadFileForIpfs(this, cid);
ui->ipfsText->setText(QString::fromStdString(cid));
}

Expand Down
37 changes: 37 additions & 0 deletions src/qt/httpclient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Created by tri on 8/7/24.
//

#include <qt/httpclient.h>

#include <QNetworkReply>
#include <QNetworkRequest>
#include <util/system.h>

HttpClient::HttpClient(QObject* parent) : QObject(parent) {
manager = new QNetworkAccessManager(this);
//connect(manager, &QNetworkAccessManager::finished, this, &HttpClient::onFinished);
}

HttpClient::~HttpClient() {
delete manager;
}

void HttpClient::sendGetRequest(const std::string& cid, std::function<void(const QByteArray&)> callback) {
std::string downUrl = gArgs.GetArg("-ipfsservice", DEFAULT_IPFS_SERVICE_URL) + "get/" + cid;
QNetworkRequest request(QUrl(QString::fromStdString(downUrl)));
QNetworkReply* reply = manager->get(request);
connect(reply, &QNetworkReply::finished, this, [callback, reply]() {
if (reply->error() == QNetworkReply::NoError) {
QByteArray responseData = reply->readAll();
callback(responseData);
} else {
callback(QByteArray::fromStdString(""));
}
reply->deleteLater();
});
}

void HttpClient::sendFileRequest(const QUrl& url, const QString& filePath) {

}
38 changes: 38 additions & 0 deletions src/qt/httpclient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// Created by tri on 8/7/24.
//

#ifndef RAPTOREUM_HTTPCLIENT_H
#define RAPTOREUM_HTTPCLIENT_H

#include <QObject>
#include <QUrl>
#include <QString>
#include <QByteArray>
#include <QNetworkAccessManager>
#include <string>

namespace Ui {
class HttpClient;
}

QT_BEGIN_NAMESPACE
class QNetworkAccessManager;
QT_END_NAMESPACE

class HttpClient : public QObject {
Q_OBJECT

public:
explicit HttpClient(QObject* parent = nullptr);
~HttpClient();
void sendFileRequest(const QUrl& url, const QString& filePath);
void sendGetRequest(const std::string& cid, std::function<void(const QByteArray&)> callback);
//private slots:
// void onFinished(QNetworkReply* reply);

private:
QNetworkAccessManager* manager;
};

#endif //RAPTOREUM_HTTPCLIENT_H
6 changes: 4 additions & 2 deletions src/qt/updateassetsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/sendassetsentry.h>
#include <qt/upload_download.h>
//#include <qt/upload_download.h>
#include <qt/uploaddownload.h>

#include <chainparams.h>
#include <interfaces/node.h>
Expand Down Expand Up @@ -240,7 +241,8 @@ void UpdateAssetsDialog::on_updateAssetButton_clicked() {
}

void UpdateAssetsDialog::openFilePicker() {
std::string cid = pickAndSendFileForIpfs(this);
std::string cid;
pickAndUploadFileForIpfs(this, cid);
ui->ipfsText->setText(QString::fromStdString(cid));
}

Expand Down
163 changes: 163 additions & 0 deletions src/qt/uploaddownload.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//
// Created by tri on 8/8/24.
//

#include <qt/uploaddownload.h>

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/connect.hpp>
#include <boost/stacktrace.hpp>
#include <QString>
#include <QFileDialog>
#include <filesystem>

namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
namespace ssl = net::ssl; // from <boost/asio/ssl.hpp>
using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>

ssl::context setup_ssl_context() {
ssl::context ctx{ssl::context::tlsv12_client};
ctx.set_options(
ssl::context::default_workarounds |
ssl::context::no_sslv3 |
ssl::context::no_tlsv1 |
ssl::context::no_tlsv1_1 |
ssl::context::single_dh_use
);
return ctx;
}

beast::ssl_stream<beast::tcp_stream> create_and_connect_ssl_stream(net::io_context& ioc, const std::string& host, const std::string& port, ssl::context& ctx) {
tcp::resolver resolver{ioc};
beast::ssl_stream<beast::tcp_stream> stream{ioc, ctx};

if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {
beast::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
throw beast::system_error{ec};
}

auto const results = resolver.resolve(host, port);
beast::get_lowest_layer(stream).connect(results);
stream.handshake(ssl::stream_base::client);

return stream;
}

template <typename Body>
std::string write_response(beast::ssl_stream<beast::tcp_stream>& stream, http::request<Body>& req) {
try {
// Send the HTTP request to the remote host
http::write(stream, req);

// Declare a container to hold the response
beast::flat_buffer buffer;
http::response<http::dynamic_body> res;
http::read(stream, buffer, res);

// Output the response
std::ostringstream response_stream;
response_stream << beast::buffers_to_string(res.body().data());
return response_stream.str();
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
throw;
}
}

std::string generate_boundary() {
static const char alphanum[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const size_t len = 32;
std::string boundary;
boundary.reserve(len);

for (size_t i = 0; i < len; ++i) {
boundary += alphanum[rand() % (sizeof(alphanum) - 1)];
}
return boundary;
}

void graceful_disconnect(beast::ssl_stream<beast::tcp_stream>& stream) {
beast::error_code ec;
stream.shutdown(ec);
if (ec && ec != boost::asio::error::eof && ec != boost::asio::ssl::error::stream_truncated) {
throw boost::system::system_error{ec};
}
}

void download(const std::string cid, std::string& response_data) {
std::string getTarget = GET_URI + cid;
try {
net::io_context ioc;
ssl::context ctx = setup_ssl_context();
beast::ssl_stream<beast::tcp_stream> stream = create_and_connect_ssl_stream(ioc, IPFS_SERVICE_HOST, "443", ctx);

http::request<http::empty_body> req{http::verb::get, getTarget, 11};
req.set(http::field::host, IPFS_SERVICE_HOST);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);

response_data = write_response(stream, req);
graceful_disconnect(stream);
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
LogPrintf("Error: %s \n", e.what());
}
}

void upload(const std::string& file_path, std::string& response_data) {
try {
net::io_context ioc;
ssl::context ctx = setup_ssl_context();
beast::ssl_stream <beast::tcp_stream> stream = create_and_connect_ssl_stream(ioc, IPFS_SERVICE_HOST, "443", ctx);

// Generate a boundary for the multipart form data
std::string boundary = generate_boundary();

// Read the file content
std::ifstream file(file_path, std::ios::binary);
if (!file) {
throw std::runtime_error("Failed to open file");
}
std::filesystem::path full_path = file_path;
std::string file_content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());

// Create the multipart form data body
std::ostringstream body;
body << "--" << boundary << "\r\n";
body << "Content-Disposition: form-data; name=\"file\"; filename=\"" << full_path.filename().string() << "\"\r\n";
body << "Content-Type: application/octet-stream\r\n\r\n";
body << file_content << "\r\n";
body << "--" << boundary << "--\r\n";

std::string body_str = body.str();

http::request <http::string_body> req{http::verb::post, UPLOAD_URI, 11};
req.set(http::field::host, IPFS_SERVICE_HOST);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.set(http::field::content_type, "multipart/form-data; boundary=" + boundary);
req.set(http::field::content_length, std::to_string(body_str.size()));
req.body() = body_str;

response_data = write_response(stream, req);

graceful_disconnect(stream);
} catch (const std::exception &e) {
LogPrintf("Error: %s", e.what());
response_data = e.what();
}
}

void pickAndUploadFileForIpfs(QWidget *qWidget, std::string& cid) {
QString filePath = QFileDialog::getOpenFileName(qWidget, "Open File", "", "All Files (*.*)");
if (!filePath.isEmpty()) {
std::string filePathStr = filePath.toStdString();
upload(filePathStr, cid);
}
}
Loading

0 comments on commit a8fcfdb

Please sign in to comment.