--- a/CMakeLists.txt Sat Mar 12 02:03:44 2022 +0100
+++ b/CMakeLists.txt Sat Mar 12 20:48:25 2022 +0100
@@ -1,5 +1,5 @@
# Relational pipes
-# Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+# Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
--- a/bash-completion.sh Sat Mar 12 02:03:44 2022 +0100
+++ b/bash-completion.sh Sat Mar 12 20:48:25 2022 +0100
@@ -1,5 +1,5 @@
# Relational pipes
-# Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info)
+# Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
--- a/nbproject/configurations.xml Sat Mar 12 02:03:44 2022 +0100
+++ b/nbproject/configurations.xml Sat Mar 12 20:48:25 2022 +0100
@@ -42,6 +42,8 @@
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
<df root="." name="0">
<df name="src">
+ <in>HTTPClient.cpp</in>
+ <in>HTTPClient.h</in>
<in>relpipe-tr-http.cpp</in>
</df>
</df>
@@ -94,6 +96,10 @@
<preBuildFirst>true</preBuildFirst>
</preBuild>
</makefileType>
+ <item path="src/HTTPClient.cpp" ex="false" tool="1" flavor2="0">
+ </item>
+ <item path="src/HTTPClient.h" ex="false" tool="3" flavor2="0">
+ </item>
<item path="src/relpipe-tr-http.cpp" ex="false" tool="1" flavor2="0">
<ccTool flags="0">
</ccTool>
@@ -134,6 +140,10 @@
<preBuildFirst>true</preBuildFirst>
</preBuild>
</makefileType>
+ <item path="src/HTTPClient.cpp" ex="false" tool="1" flavor2="0">
+ </item>
+ <item path="src/HTTPClient.h" ex="false" tool="3" flavor2="0">
+ </item>
<item path="src/relpipe-tr-http.cpp" ex="false" tool="1" flavor2="0">
<ccTool flags="0">
</ccTool>
--- a/src/CLIParser.h Sat Mar 12 02:03:44 2022 +0100
+++ b/src/CLIParser.h Sat Mar 12 20:48:25 2022 +0100
@@ -1,6 +1,6 @@
/**
* Relational pipes
- * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+ * Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- a/src/CMakeLists.txt Sat Mar 12 02:03:44 2022 +0100
+++ b/src/CMakeLists.txt Sat Mar 12 20:48:25 2022 +0100
@@ -1,5 +1,5 @@
# Relational pipes
-# Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+# Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@
# Executable output:
add_executable(
${EXECUTABLE_FILE}
+ HTTPClient.cpp
relpipe-tr-http.cpp
)
--- a/src/Configuration.h Sat Mar 12 02:03:44 2022 +0100
+++ b/src/Configuration.h Sat Mar 12 20:48:25 2022 +0100
@@ -1,6 +1,6 @@
/**
* Relational pipes
- * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+ * Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HTTPClient.cpp Sat Mar 12 20:48:25 2022 +0100
@@ -0,0 +1,84 @@
+/**
+ * Relational pipes
+ * Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sstream>
+
+#include <curl/curl.h>
+
+#include "HTTPClient.h"
+
+
+namespace relpipe {
+namespace tr {
+namespace http {
+
+class HTTPClient::HTTPClientImpl {
+public:
+ CURL* curl;
+ std::stringstream responseBody;
+ std::vector<std::string> responseHeaders;
+
+ HTTPClientImpl(CURL* curl) : curl(curl) {
+ }
+
+ static size_t curlWriteCallback(char* buffer, size_t size, size_t nmemb, HTTPClient::HTTPClientImpl * impl) {
+ size_t r = size * nmemb;
+ impl->responseBody.write(buffer, r);
+ return r;
+ }
+
+};
+
+HTTPClient* HTTPClient::open() {
+ return new HTTPClient(new HTTPClient::HTTPClientImpl(curl_easy_init()));
+}
+
+HTTPClient::~HTTPClient() {
+ curl_easy_cleanup(impl->curl);
+ delete impl;
+}
+
+const HTTPClient::Response HTTPClient::exchange(const Request& request) {
+ HTTPClient::Response response;
+
+ // TODO: set request headers
+ // TODO: set request method
+ // TODO: get response headers
+
+ curl_easy_setopt(impl->curl, CURLOPT_URL, request.url.c_str());
+
+ curl_easy_setopt(impl->curl, CURLOPT_WRITEDATA, impl);
+ curl_easy_setopt(impl->curl, CURLOPT_WRITEFUNCTION, HTTPClientImpl::curlWriteCallback);
+
+ // curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);
+ // curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headersCurlCallback);
+
+ curl_easy_perform(impl->curl);
+
+ curl_easy_getinfo(impl->curl, CURLINFO_RESPONSE_CODE, &response.responseCode);
+ response.success = response.responseCode >= 200 && response.responseCode <= 299;
+
+ response.body = impl->responseBody.str();
+ impl->responseBody = std::stringstream();
+
+ return response;
+}
+
+
+}
+}
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/HTTPClient.h Sat Mar 12 20:48:25 2022 +0100
@@ -0,0 +1,82 @@
+/**
+ * Relational pipes
+ * Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <relpipe/common/type/typedefs.h>
+
+
+namespace relpipe {
+namespace tr {
+namespace http {
+
+/**
+ * Simple synchronous client for the HTTP and HTTPS protocol.
+ * Is not thread-safe – must not be called from multiple threads simultaneously.
+ */
+class HTTPClient {
+private:
+ class HTTPClientImpl;
+ HTTPClientImpl* impl;
+
+ HTTPClient(HTTPClientImpl* impl) : impl(impl) {
+ }
+
+
+public:
+
+ enum class Method {
+ GET,
+ HEAD,
+ POST,
+ PUT,
+ DELETE,
+ // CONNECT,
+ // OPTIONS,
+ // TRACE,
+ PATCH,
+ };
+
+ struct Request {
+ Method method = Method::GET;
+ std::string url;
+ std::vector<std::string> headers;
+ std::string body;
+ };
+
+ struct Response {
+ bool success = false;
+ int responseCode = 0;
+ std::vector<std::string> headers;
+ std::string body;
+ };
+
+ virtual ~HTTPClient();
+ HTTPClient(const HTTPClient&) = delete;
+ HTTPClient& operator=(const HTTPClient&) = delete;
+
+ static HTTPClient* open();
+
+ const Response exchange(const Request& request);
+
+};
+
+}
+}
+}
--- a/src/HTTPHandler.h Sat Mar 12 02:03:44 2022 +0100
+++ b/src/HTTPHandler.h Sat Mar 12 20:48:25 2022 +0100
@@ -1,6 +1,6 @@
/**
* Relational pipes
- * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+ * Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +36,7 @@
#include <relpipe/cli/RelpipeCLIException.h>
#include "Configuration.h"
+#include "HTTPClient.h"
namespace relpipe {
namespace tr {
@@ -51,29 +52,6 @@
size_t currentAttributeIndex = 0;
size_t currentRecordNumber = 1;
- void writeCallback(std::string value) {
- // TODO: write this attribute even if this method was not called
- // TODO: support also binary data or other encodings, not only UTF-8 text
- relationalWriter->writeAttribute(convertor.from_bytes(value));
- }
-
- static uint writeCurlCallback(char* buffer, size_t size, size_t nmemb, HTTPHandler* instance) {
- size_t r = size * nmemb;
- instance->writeCallback(std::string(buffer, r));
- return r;
- }
-
- void headersCallback(std::string value) {
- // TODO: parse name=value and store for later use
- std::cerr << std::endl << "HTTP response headers:" << std::endl << ">>>" << value << "<<<" << std::endl << "--------" << std::endl;
- }
-
- static uint headersCurlCallback(char* buffer, size_t size, size_t nmemb, HTTPHandler* instance) {
- size_t r = size * nmemb;
- instance->headersCallback(std::string(buffer, r));
- return r;
- }
-
public:
HTTPHandler(shared_ptr<relpipe::writer::RelationalWriter> relationalWriter, Configuration configuration) : relationalWriter(relationalWriter), configuration(configuration) {
@@ -96,34 +74,30 @@
relationalWriter->startRelation(name + L"_curl_response",{
{L"url", relpipe::writer::TypeId::STRING},
{L"body", relpipe::writer::TypeId::STRING},
- {L"response_code", relpipe::writer::TypeId::INTEGER}
+ {L"response_code", relpipe::writer::TypeId::INTEGER},
+ // {L"success", relpipe::writer::TypeId::BOOLEAN},
}, true);
}
void attribute(const relpipe::common::type::StringX& value) override {
- relationalWriter->writeAttribute(value);
-
- std::string url = convertor.to_bytes(value);
- relpipe::common::type::Integer responseCode = 0;
+ std::shared_ptr<HTTPClient> http(HTTPClient::open());
- CURL* curl = curl_easy_init();
- curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
-
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCurlCallback);
+ HTTPClient::Request request;
+ request.method = HTTPClient::Method::GET;
+ request.url = convertor.to_bytes(value);
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headersCurlCallback);
-
- curl_easy_perform(curl);
+ HTTPClient::Response response = http->exchange(request);
+ relpipe::common::type::Integer responseCode = response.responseCode;
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
+ // std::cerr << "url = >>>" << convertor.to_bytes(value) << "<<<" << std::endl;
+ // std::cerr << "body = >>>" << response.body << "<<<" << std::endl;
- curl_easy_cleanup(curl);
-
+ relationalWriter->writeAttribute(value);
+ relationalWriter->writeAttribute(convertor.from_bytes(response.body));
relationalWriter->writeAttribute(&responseCode, typeid (responseCode));
+ // relationalWriter->writeAttribute(&response.success, typeid (response.success));
}
void endOfPipe() {
--- a/src/relpipe-tr-http.cpp Sat Mar 12 02:03:44 2022 +0100
+++ b/src/relpipe-tr-http.cpp Sat Mar 12 20:48:25 2022 +0100
@@ -1,6 +1,6 @@
/**
* Relational pipes
- * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+ * Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by