From 61b8cdc3d40e9d6206a440eb6b9b342b8e07ea2a Mon Sep 17 00:00:00 2001 From: Victor Vazquez Date: Thu, 2 Apr 2020 11:05:26 -0700 Subject: [PATCH] Adding curl and nohttp transport options (#54) * http client --- CMakeLists.txt | 3 + sdk/core/azure-core/CMakeLists.txt | 1 + sdk/core/azure-core/inc/http/http.hpp | 174 ++++++++++++++++++ sdk/core/azure-core/inc/http/request.hpp | 147 --------------- sdk/core/azure-core/inc/http/response.hpp | 65 ------- sdk/core/azure-core/src/http/request.cpp | 27 ++- sdk/core/azure-core/src/http/response.cpp | 14 +- sdk/core/azure-core/test/CMakeLists.txt | 10 +- sdk/core/azure-core/test/main.cpp | 1 - sdk/platform/http_client/curl/CMakeLists.txt | 32 ++++ sdk/platform/http_client/curl/LICENSE | 21 +++ .../http_client/curl/inc/curl_client.hpp | 39 ++++ .../curl/src/azure_transport_curl.cpp | 15 ++ .../http_client/curl/src/curl_client.cpp | 36 ++++ .../http_client/nohttp/CMakeLists.txt | 23 +++ sdk/platform/http_client/nohttp/LICENSE | 21 +++ .../nohttp/src/azure_transport_nohttp.cpp | 13 ++ sdk/samples/http_client/curl/CMakeLists.txt | 20 ++ .../curl/src/azure_core_with_curl.cpp | 38 ++++ 19 files changed, 460 insertions(+), 240 deletions(-) delete mode 100644 sdk/core/azure-core/inc/http/request.hpp delete mode 100644 sdk/core/azure-core/inc/http/response.hpp create mode 100644 sdk/platform/http_client/curl/CMakeLists.txt create mode 100644 sdk/platform/http_client/curl/LICENSE create mode 100644 sdk/platform/http_client/curl/inc/curl_client.hpp create mode 100644 sdk/platform/http_client/curl/src/azure_transport_curl.cpp create mode 100644 sdk/platform/http_client/curl/src/curl_client.cpp create mode 100644 sdk/platform/http_client/nohttp/CMakeLists.txt create mode 100644 sdk/platform/http_client/nohttp/LICENSE create mode 100644 sdk/platform/http_client/nohttp/src/azure_transport_nohttp.cpp create mode 100644 sdk/samples/http_client/curl/CMakeLists.txt create mode 100644 sdk/samples/http_client/curl/src/azure_core_with_curl.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a84f3a9f..11fe8aa32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,3 +37,6 @@ include(global_compile_options) # sub-projects add_subdirectory(sdk/core/azure-core) +add_subdirectory(sdk/platform/http_client/curl) # will work only if BUILD_CURL_TRANSPORT=ON +add_subdirectory(sdk/samples/http_client/curl) # will work only if BUILD_CURL_TRANSPORT=ON +add_subdirectory(sdk/platform/http_client/nohttp) # will work only if !BUILD_CURL_TRANSPORT=ON diff --git a/sdk/core/azure-core/CMakeLists.txt b/sdk/core/azure-core/CMakeLists.txt index 95e821f6e..159bc0fad 100644 --- a/sdk/core/azure-core/CMakeLists.txt +++ b/sdk/core/azure-core/CMakeLists.txt @@ -12,6 +12,7 @@ add_library ( src/credentials/credentials src/http/http src/http/request + src/http/response ) target_include_directories (azure-core PUBLIC $ $) diff --git a/sdk/core/azure-core/inc/http/http.hpp b/sdk/core/azure-core/inc/http/http.hpp index 1e9871736..c091ca6b1 100644 --- a/sdk/core/azure-core/inc/http/http.hpp +++ b/sdk/core/azure-core/inc/http/http.hpp @@ -4,8 +4,11 @@ #pragma once #include +#include #include +#include #include +#include #include @@ -63,6 +66,177 @@ enum class HttpMethod PATCH, }; +class Request +{ + +private: + // query needs to be first or at least before url, since url might update it + std::map m_queryParameters; + + HttpMethod _method; + std::string _url; + std::map m_headers; + std::map m_retryHeaders; + std::map m_retryQueryParameters; + // Request can contain no body, or either of next bodies (_bodyBuffer plus size or bodyStream) + BodyStream* m_bodyStream; + BodyBuffer* m_bodyBuffer; + + // flag to know where to insert header + bool m_retryModeEnabled; + + // returns left map plus all items in right + // when duplicates, left items are preferred + static std::map mergeMaps( + std::map left, + std::map const& right) + { + left.insert(right.begin(), right.end()); + return left; + } + + /** + * Will check if there are any query parameter in url looking for symbol '?' + * If it is found, it will insert query parameters to m_queryParameters internal field + * and remove it from url + */ + const std::string parseUrl(std::string const& url) + { + + const auto firstPosition = std::find(url.begin(), url.end(), '?'); + if (firstPosition == url.end()) + { + return url; // not query parameters + } + + auto position = firstPosition; // position of symbol ? + while (position != url.end()) + { + ++position; // skip over the ? or & + const auto nextPosition = std::find(position, url.end(), '&'); + const auto equalChar = std::find(position, nextPosition, '='); + auto valueStart = equalChar; + if (valueStart != nextPosition) + { + ++valueStart; // skip = symbol + } + + // Note: if there is another = symbol before nextPosition, it will be part of the paramenter + // value. And if there is not a ? symbol, we add empty string as value + m_queryParameters.insert(std::pair( + std::string(position, equalChar), std::string(valueStart, nextPosition))); + + position = nextPosition; + } + + return std::string(url.begin(), firstPosition); + } + + Request( + HttpMethod httpMethod, + std::string const& url, + BodyStream* bodyStream, + BodyBuffer* bodyBuffer) + : _method(std::move(httpMethod)), _url(parseUrl(url)), m_bodyStream(bodyStream), + m_bodyBuffer(bodyBuffer), m_retryModeEnabled(false) + { + // TODO: parse url + } + +public: + Request(HttpMethod httpMethod, std::string const& url) + : Request(httpMethod, url, BodyStream::null, BodyBuffer::null) + { + } + + Request(HttpMethod httpMethod, std::string const& url, BodyBuffer* bodyBuffer) + : Request(httpMethod, url, BodyStream::null, bodyBuffer) + { + } + + Request(HttpMethod httpMethod, std::string const& url, BodyStream* bodyStream) + : Request(httpMethod, url, bodyStream, BodyBuffer::null) + { + } + + // Methods used to build HTTP request + void addPath(std::string const& path); + void addQueryParameter(std::string const& name, std::string const& value); + void addHeader(std::string const& name, std::string const& value); + void startRetry(); // only called by retry policy + + // Methods used by transport layer (and logger) to send request + HttpMethod getMethod(); + std::string getEncodedUrl(); // should return encoded url + std::map getHeaders(); + BodyStream* getBodyStream(); + BodyBuffer* getBodyBuffer(); +}; + +/* + * Response exceptions + */ +struct CouldNotResolveHostException : public std::exception +{ + const char* what() const throw() { return "couldnt resolve host"; } +}; +struct ErrorWhileWrittingResponse : public std::exception +{ + const char* what() const throw() { return "couldnt write response"; } +}; +// Any other excpetion from transport layer without an specific exception defined above +struct TransportException : public std::exception +{ + const char* what() const throw() { return "Error on transport layer while sending request"; } +}; + +class Response +{ + +private: + uint16_t m_statusCode; + std::string m_reasonPhrase; + std::map m_headers; + + // Response can contain no body, or either of next bodies (_bodyBuffer plus size or bodyStream) + http::BodyBuffer* m_bodyBuffer; + http::BodyStream* m_bodyStream; + + Response( + uint16_t statusCode, + std::string const& reasonPhrase, + BodyBuffer* const bodyBuffer, + BodyStream* const BodyStream) + : m_statusCode(statusCode), m_reasonPhrase(reasonPhrase), m_bodyBuffer(bodyBuffer), + m_bodyStream(BodyStream) + { + } + +public: + Response(uint16_t statusCode, std::string const& reasonPhrase) + : Response(statusCode, reasonPhrase, http::BodyBuffer::null, http::BodyStream::null) + { + } + + // Methods used to build HTTP response + void addHeader(std::string const& name, std::string const& value); + void setBody(BodyBuffer* bodyBuffer); + void setBody(BodyStream* bodyStream); + + // Methods used by transport layer (and logger) to send response + uint16_t getStatusCode(); + std::string const& getReasonPhrase(); + std::map const& getHeaders(); + http::BodyStream* getBodyStream(); + http::BodyBuffer* getBodyBuffer(); +}; + +class Client +{ +public: + static Response send(Request& request); +}; + } // namespace http } // namespace core } // namespace azure diff --git a/sdk/core/azure-core/inc/http/request.hpp b/sdk/core/azure-core/inc/http/request.hpp deleted file mode 100644 index 760684a37..000000000 --- a/sdk/core/azure-core/inc/http/request.hpp +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// SPDX-License-Identifier: MIT - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -namespace azure -{ -namespace core -{ -namespace http -{ - -class Request -{ - -private: - Request(Request const&) = delete; - void operator=(Request const&) = delete; - - // query needs to be first or at least before url, since url might update it - std::map _queryParameters; - - HttpMethod _method; - std::string _url; - std::map _headers; - std::map _retryHeaders; - std::map _retryQueryParameters; - // Request can contain no body, or either of next bodies (_bodyBuffer plus size or bodyStream) - BodyStream* _bodyStream; - BodyBuffer* _bodyBuffer; - - // flag to know where to insert header - bool _retryModeEnabled; - - // returns left map plus all items in right - // when duplicates, left items are preferred - static std::map mergeMaps( - std::map const& left, - std::map const& right) - { - auto result = std::map(left); - std::for_each(right.begin(), right.end(), [&](auto const& pair) { result.insert(pair); }); - return result; - } - - /** - * Create an stream from source string. Then use getline and separator to get as many tokens as - * possible and insert each one to result vector - */ - static std::vector split(std::string source, char separator) - { - auto result = std::vector(); - - auto stringAsStream = std::stringstream(source); - auto token = std::string(); - - while (std::getline(stringAsStream, token, separator)) - { - result.push_back(token); - } - return result; - } - - /** - * Will check if there are any query parameter in url looking for symbol '?' - * If it is found, it will insert query parameters to _queryParameters internal field - * and remove it from url - */ - std::string parseUrl(std::string url) - { - auto position = url.find('?'); - - if (position == std::string::npos) - { - return url; // no query parameters. Nothing else to do - } - - // Get query parameters string and update - auto queryParameters = url.substr(position + 1); - url = url.substr(0, position); - - // Split all query parameters (should be separated by &) - auto queryParametersVector = split(queryParameters, '&'); - - // insert each query parameter to internal field - std::for_each(queryParametersVector.begin(), queryParametersVector.end(), [&](auto query) { - auto parameter = split(query, '='); - // Will throw if parameter in query is not valid (i.e. arg:1) - _queryParameters.insert(std::pair(parameter[0], parameter[1])); - }); - - return url; - } - - Request( - HttpMethod httpMethod, - std::string const& url, - BodyStream* bodyStream, - BodyBuffer* bodyBuffer) - : _method(std::move(httpMethod)), _url(parseUrl(std::move(url))), _bodyStream(bodyStream), - _bodyBuffer(bodyBuffer), _retryModeEnabled(false) - { - // TODO: parse url - } - -public: - Request(HttpMethod httpMethod, std::string const& url) - : Request(httpMethod, url, BodyStream::null, BodyBuffer::null) - { - } - - Request(HttpMethod httpMethod, std::string const& url, BodyBuffer* bodyBuffer) - : Request(httpMethod, url, BodyStream::null, bodyBuffer) - { - } - - Request(HttpMethod httpMethod, std::string const& url, BodyStream* bodyStream) - : Request(httpMethod, url, bodyStream, BodyBuffer::null) - { - } - - // Methods used to build HTTP request - void addPath(std::string const& path); - void addQueryParameter(std::string const& name, std::string const& value); - void addHeader(std::string const& name, std::string const& value); - void startRetry(); // only called by retry policy - - // Methods used by transport layer (and logger) to send request - HttpMethod getMethod(); - std::string getEncodedUrl(); // should return encoded url - std::map getHeaders(); - BodyStream* getBodyStream(); - BodyBuffer* getBodyBuffer(); -}; - -} // namespace http -} // namespace core -} // namespace azure diff --git a/sdk/core/azure-core/inc/http/response.hpp b/sdk/core/azure-core/inc/http/response.hpp deleted file mode 100644 index 91577bc3a..000000000 --- a/sdk/core/azure-core/inc/http/response.hpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// SPDX-License-Identifier: MIT - -#pragma once - -#include -#include -#include - -#include - -namespace azure -{ -namespace core -{ -namespace http -{ - -class Response -{ - -private: - Response(Response const&) = delete; - void operator=(Response const&) = delete; - - uint16_t _statusCode; - std::string _reasonPhrase; - std::map _headers; - - // Response can contain no body, or either of next bodies (_bodyBuffer plus size or bodyStream) - BodyBuffer& _bodyBuffer; - BodyStream& _bodyStream; - - Response( - uint16_t statusCode, - std::string reasonPhrase, - BodyBuffer& const bodyBuffer, - BodyStream& const BodyStream) - : _statusCode(statusCode), _reasonPhrase(reasonPhrase), _bodyBuffer(bodyBuffer), - _bodyStream(BodyStream) - { - } - -public: - Response(uint16_t statusCode, std::string reasonPhrase) - : Response(statusCode, reasonPhrase, BodyBuffer::null, BodyStream::null) - { - } - - // Methods used to build HTTP response - void addHeader(std::string const& name, std::string const& value); - void setBody(BodyBuffer& const bodyBuffer); - void setBody(BodyStream& const bodyStream); - - // Methods used by transport layer (and logger) to send response - uint16_t const& getStatusCode(); - std::string const& getReasonPhrase(); - std::map const& getHeaders(); - http::BodyStream& getBodyStream(); - http::BodyBuffer& getBodyBuffer(); -}; - -} // namespace http -} // namespace core -} // namespace azure diff --git a/sdk/core/azure-core/src/http/request.cpp b/sdk/core/azure-core/src/http/request.cpp index 8a607813a..68e910180 100644 --- a/sdk/core/azure-core/src/http/request.cpp +++ b/sdk/core/azure-core/src/http/request.cpp @@ -6,7 +6,6 @@ #include #include -#include using namespace azure::core::http; @@ -14,47 +13,47 @@ void Request::addPath(std::string const& path) { this->_url += "/" + path; } void Request::addQueryParameter(std::string const& name, std::string const& value) { - if (this->_retryModeEnabled) + if (this->m_retryModeEnabled) { // When retry mode is ON, any new value must override previous - this->_retryQueryParameters[name] = value; + this->m_retryQueryParameters[name] = value; } else { - this->_queryParameters.insert(std::pair(name, value)); + this->m_queryParameters.insert(std::pair(name, value)); } } void Request::addHeader(std::string const& name, std::string const& value) { - if (this->_retryModeEnabled) + if (this->m_retryModeEnabled) { // When retry mode is ON, any new value must override previous - this->_retryHeaders[name] = value; + this->m_retryHeaders[name] = value; } else { - this->_headers.insert(std::pair(name, value)); + this->m_headers.insert(std::pair(name, value)); } } void Request::startRetry() { - this->_retryModeEnabled = true; - this->_retryHeaders.clear(); + this->m_retryModeEnabled = true; + this->m_retryHeaders.clear(); } HttpMethod Request::getMethod() { return this->_method; } std::string Request::getEncodedUrl() { - if (this->_queryParameters.size() == 0 && this->_retryQueryParameters.size() == 0) + if (this->m_queryParameters.size() == 0 && this->m_retryQueryParameters.size() == 0) { return _url; // no query parameters to add } // remove query duplicates - auto queryParameters = Request::mergeMaps(this->_retryQueryParameters, this->_queryParameters); + auto queryParameters = Request::mergeMaps(this->m_retryQueryParameters, this->m_queryParameters); // build url auto queryString = std::string(""); for (auto pair : queryParameters) @@ -69,9 +68,9 @@ std::map Request::getHeaders() { // create map with retry headers witch are the most important and we don't want // to override them with any duplicate header - return Request::mergeMaps(this->_retryHeaders, this->_headers); + return Request::mergeMaps(this->m_retryHeaders, this->m_headers); } -BodyStream* Request::getBodyStream() { return _bodyStream; } +BodyStream* Request::getBodyStream() { return m_bodyStream; } -BodyBuffer* Request::getBodyBuffer() { return _bodyBuffer; } +BodyBuffer* Request::getBodyBuffer() { return m_bodyBuffer; } diff --git a/sdk/core/azure-core/src/http/response.cpp b/sdk/core/azure-core/src/http/response.cpp index d26ca5522..dec7da0e0 100644 --- a/sdk/core/azure-core/src/http/response.cpp +++ b/sdk/core/azure-core/src/http/response.cpp @@ -6,19 +6,15 @@ #include #include -#include using namespace azure::core::http; -BodyStream& BodyStream::null = *(BodyStream*)NULL; -BodyBuffer& BodyBuffer::null = *(BodyBuffer*)NULL; +uint16_t Response::getStatusCode() { return m_statusCode; } -uint16_t const& Response::getStatusCode() { return _statusCode; } +std::string const& Response::getReasonPhrase() { return m_reasonPhrase; } -std::string const& Response::getReasonPhrase() { return _reasonPhrase; } +std::map const& Response::getHeaders() { return this->m_headers; } -std::map const& Response::getHeaders() { return this->_headers; } +BodyStream* Response::getBodyStream() { return m_bodyStream; } -BodyStream& Response::getBodyStream() { return _bodyStream; } - -BodyBuffer& Response::getBodyBuffer() { return _bodyBuffer; } +BodyBuffer* Response::getBodyBuffer() { return m_bodyBuffer; } diff --git a/sdk/core/azure-core/test/CMakeLists.txt b/sdk/core/azure-core/test/CMakeLists.txt index ec93504ac..0bded533b 100644 --- a/sdk/core/azure-core/test/CMakeLists.txt +++ b/sdk/core/azure-core/test/CMakeLists.txt @@ -5,15 +5,17 @@ cmake_minimum_required (VERSION 3.12) include(AddGoogleTest) -project (azure-core-test LANGUAGES CXX) +set(TARGET_NAME "azure-core-test") + +project (${TARGET_NAME} LANGUAGES CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) add_executable ( - azure-core-test + ${TARGET_NAME} main.cpp ) -target_link_libraries(azure-core-test PRIVATE azure-core) -add_gtest(azure-core-test) +target_link_libraries(${TARGET_NAME} PRIVATE azure-core) +add_gtest(${TARGET_NAME}) diff --git a/sdk/core/azure-core/test/main.cpp b/sdk/core/azure-core/test/main.cpp index c51ec3a16..73fcb0253 100644 --- a/sdk/core/azure-core/test/main.cpp +++ b/sdk/core/azure-core/test/main.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MIT #include -#include #include #include "gtest/gtest.h" diff --git a/sdk/platform/http_client/curl/CMakeLists.txt b/sdk/platform/http_client/curl/CMakeLists.txt new file mode 100644 index 000000000..a59737f5c --- /dev/null +++ b/sdk/platform/http_client/curl/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +if (BUILD_CURL_TRANSPORT) + +cmake_minimum_required (VERSION 3.12) +set(TARGET_NAME "azure-transport-curl") + +project(${TARGET_NAME} LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +find_package(CURL CONFIG) +if(NOT CURL_FOUND) + find_package(CURL REQUIRED) +endif() + +add_library ( + ${TARGET_NAME} STATIC + src/azure_transport_curl + src/curl_client + ) + +target_include_directories (${TARGET_NAME} PRIVATE $ $) + +# make sure that users can consume the project as a library. +add_library (azure::curl ALIAS ${TARGET_NAME}) + +target_include_directories(${TARGET_NAME} PUBLIC ${CURL_INCLUDE_DIRS}) +target_link_libraries(${TARGET_NAME} PRIVATE azure-core CURL::libcurl) + +endif() diff --git a/sdk/platform/http_client/curl/LICENSE b/sdk/platform/http_client/curl/LICENSE new file mode 100644 index 000000000..51b6a76e5 --- /dev/null +++ b/sdk/platform/http_client/curl/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/sdk/platform/http_client/curl/inc/curl_client.hpp b/sdk/platform/http_client/curl/inc/curl_client.hpp new file mode 100644 index 000000000..5eaf1c4b1 --- /dev/null +++ b/sdk/platform/http_client/curl/inc/curl_client.hpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +class CurlClient +{ +private: + azure::core::http::Request& m_request; + CURL* m_p_curl; + + // setHeaders() + CURLcode setUrl() + { + return curl_easy_setopt(m_p_curl, CURLOPT_URL, this->m_request.getEncodedUrl().c_str()); + } + CURLcode perform() + { + auto settingUp = setUrl(); + if (settingUp != CURLE_OK) + { + return settingUp; + } + return curl_easy_perform(m_p_curl); + } + +public: + CurlClient(azure::core::http::Request& request) : m_request(request) + { + m_p_curl = curl_easy_init(); + } + // client curl struct on destruct + ~CurlClient() { curl_easy_cleanup(m_p_curl); } + + azure::core::http::Response send(); +}; diff --git a/sdk/platform/http_client/curl/src/azure_transport_curl.cpp b/sdk/platform/http_client/curl/src/azure_transport_curl.cpp new file mode 100644 index 000000000..b1de3ec5f --- /dev/null +++ b/sdk/platform/http_client/curl/src/azure_transport_curl.cpp @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include +#include + +using namespace azure::core::http; + +// implement send method +Response Client::send(Request& request) +{ + CurlClient client(request); + // return request response + return client.send(); +} diff --git a/sdk/platform/http_client/curl/src/curl_client.cpp b/sdk/platform/http_client/curl/src/curl_client.cpp new file mode 100644 index 000000000..873389a5b --- /dev/null +++ b/sdk/platform/http_client/curl/src/curl_client.cpp @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include +#include + +#include + +using namespace azure::core::http; +using namespace std; + +Response CurlClient::send() +{ + auto performing = perform(); + + if (performing != CURLE_OK) + { + switch (performing) + { + case CURLE_COULDNT_RESOLVE_HOST: + { + throw azure::core::http::CouldNotResolveHostException(); + } + case CURLE_WRITE_ERROR: + { + throw azure::core::http::ErrorWhileWrittingResponse(); + } + default: + { + throw azure::core::http::TransportException(); + } + } + } + + return Response(200, "OK\n"); +} diff --git a/sdk/platform/http_client/nohttp/CMakeLists.txt b/sdk/platform/http_client/nohttp/CMakeLists.txt new file mode 100644 index 000000000..842de3fa0 --- /dev/null +++ b/sdk/platform/http_client/nohttp/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +if (NOT BUILD_CURL_TRANSPORT) + +cmake_minimum_required (VERSION 3.12) +set(TARGET_NAME "azure-transport-nothhp") + +project(${TARGET_NAME} LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +add_library ( + ${TARGET_NAME} STATIC + src/azure_transport_nohttp.cpp +) + +target_link_libraries(${TARGET_NAME} PRIVATE azure-core) + +# make sure that users can consume the project as a library. +add_library (azure::nohttp ALIAS ${TARGET_NAME}) + +endif() diff --git a/sdk/platform/http_client/nohttp/LICENSE b/sdk/platform/http_client/nohttp/LICENSE new file mode 100644 index 000000000..51b6a76e5 --- /dev/null +++ b/sdk/platform/http_client/nohttp/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/sdk/platform/http_client/nohttp/src/azure_transport_nohttp.cpp b/sdk/platform/http_client/nohttp/src/azure_transport_nohttp.cpp new file mode 100644 index 000000000..c798822ba --- /dev/null +++ b/sdk/platform/http_client/nohttp/src/azure_transport_nohttp.cpp @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include + +using namespace azure::core::http; + +// implement send method +Response Client::send(Request& request) +{ + (void)request; + throw; +} diff --git a/sdk/samples/http_client/curl/CMakeLists.txt b/sdk/samples/http_client/curl/CMakeLists.txt new file mode 100644 index 000000000..cae181cc1 --- /dev/null +++ b/sdk/samples/http_client/curl/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: MIT + +if (BUILD_CURL_TRANSPORT) + +cmake_minimum_required (VERSION 3.12) +set(TARGET_NAME "azure_core_with_curl") + +project(${TARGET_NAME} LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +add_executable ( + ${TARGET_NAME} + src/azure_core_with_curl +) + +target_link_libraries(${TARGET_NAME} PRIVATE azure-core azure-transport-curl) + +endif() diff --git a/sdk/samples/http_client/curl/src/azure_core_with_curl.cpp b/sdk/samples/http_client/curl/src/azure_core_with_curl.cpp new file mode 100644 index 000000000..5ca5f2f9d --- /dev/null +++ b/sdk/samples/http_client/curl/src/azure_core_with_curl.cpp @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @brief Simulates customer application that is linked with azure-core and azure-transport-curl + * + */ + +#include + +#include + +using namespace azure::core; +using namespace std; + +int main() +{ + string host("https://httpbin.org/get"); + cout << "testing curl from transport" << endl << "Host: " << host << endl; + + auto request = http::Request(http::HttpMethod::GET, host); + + try + { + auto response = http::Client::send(request); + cout << response.getReasonPhrase(); + } + catch (http::CouldNotResolveHostException& e) + { + cout << e.what() << endl; + } + catch (http::TransportException& e) + { + cout << e.what() << endl; + } + + return 0; +}