# HG changeset patch # User František Kučera # Date 1647114505 -3600 # Node ID 165f6162524dac650db972d1dab57599a507f326 # Parent 602462d04c578046ee32facfe9d754c8ff77d0a5 introduce HTTPClient wrapper around CURL diff -r 602462d04c57 -r 165f6162524d CMakeLists.txt --- 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 diff -r 602462d04c57 -r 165f6162524d bash-completion.sh --- 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 diff -r 602462d04c57 -r 165f6162524d nbproject/configurations.xml --- 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 @@ + HTTPClient.cpp + HTTPClient.h relpipe-tr-http.cpp @@ -94,6 +96,10 @@ true + + + + @@ -134,6 +140,10 @@ true + + + + diff -r 602462d04c57 -r 165f6162524d src/CLIParser.h --- 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 diff -r 602462d04c57 -r 165f6162524d src/CMakeLists.txt --- 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 ) diff -r 602462d04c57 -r 165f6162524d src/Configuration.h --- 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 diff -r 602462d04c57 -r 165f6162524d src/HTTPClient.cpp --- /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 . + */ + +#include + +#include + +#include "HTTPClient.h" + + +namespace relpipe { +namespace tr { +namespace http { + +class HTTPClient::HTTPClientImpl { +public: + CURL* curl; + std::stringstream responseBody; + std::vector 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; +} + + +} +} +} diff -r 602462d04c57 -r 165f6162524d src/HTTPClient.h --- /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 . + */ +#pragma once + +#include +#include + +#include + + +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 headers; + std::string body; + }; + + struct Response { + bool success = false; + int responseCode = 0; + std::vector headers; + std::string body; + }; + + virtual ~HTTPClient(); + HTTPClient(const HTTPClient&) = delete; + HTTPClient& operator=(const HTTPClient&) = delete; + + static HTTPClient* open(); + + const Response exchange(const Request& request); + +}; + +} +} +} diff -r 602462d04c57 -r 165f6162524d src/HTTPHandler.h --- 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 #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 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 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() { diff -r 602462d04c57 -r 165f6162524d src/relpipe-tr-http.cpp --- 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