Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support CURL based HTTP client #1182

Merged
merged 42 commits into from
Sep 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7efa590
Support CURL based HTTP client
franksinankaya Jul 10, 2019
606565f
Include buffer request for CURL based client
franksinankaya Jul 10, 2019
ea3a590
Rename to curl_xyz functions and remove if 0s
franksinankaya Jul 12, 2019
2814029
Restore ifdef
franksinankaya Jul 12, 2019
ca838be
Remove conflicting definitions
franksinankaya Jul 12, 2019
2ceebcb
Prefer utility::char_t to TCHAR
franksinankaya Jul 12, 2019
bdc6efc
Bring writedata optimization by removing the intermediate buffering
franksinankaya Jul 12, 2019
e7858d7
Use std::string where possible
franksinankaya Jul 12, 2019
2b9e778
Unify trace functions and reduce dynamic_cast calls
franksinankaya Jul 12, 2019
17c50d1
Add ubuntu 18.04 azure pipeline with no tests for the moment
franksinankaya Jul 13, 2019
fb85f5a
Use ubuntu 16.04 but update the curl in it
franksinankaya Jul 13, 2019
50ac9d4
pipelines: needs sudo for install
franksinankaya Jul 13, 2019
55bc08b
Remove reference to undefined type
franksinankaya Jul 13, 2019
ee4c0cc
Eliminate size conversations
franksinankaya Jul 15, 2019
06b5d13
Formatting changes and convert MultiByte functions to C++ native func…
franksinankaya Jul 15, 2019
cd4d172
Remove printfs
franksinankaya Jul 16, 2019
b27cb39
Move GlobalFree and make_unique to http_client_curl.cpp
franksinankaya Jul 18, 2019
d420884
Exit on build error
franksinankaya Jul 18, 2019
8e0bf83
Use unique from utility
franksinankaya Jul 21, 2019
817dd16
Use const where possible, convert reinterpret cast to static cast
franksinankaya Jul 21, 2019
44ca34a
Use nullize_newlines
franksinankaya Jul 21, 2019
e2ced5a
Structure TRACE output for each request
franksinankaya Jul 21, 2019
7055a34
Use queue instead of locks
franksinankaya Jul 21, 2019
df774d5
Simplify reads, add breadcrumbs on failure
franksinankaya Jul 23, 2019
0b8609a
Ignore http 100 continue
franksinankaya Jul 23, 2019
95bfd6b
Remove buffering support
franksinankaya Jul 26, 2019
593954c
Cleanup repeating patterns and add null checks
franksinankaya Jul 26, 2019
3ab541f
More cleanup
franksinankaya Aug 3, 2019
0345652
tests: CURL doesn't support hostname override
franksinankaya Aug 5, 2019
422655c
More function unification and prevent premature read completion
franksinankaya Aug 5, 2019
1cd5cd1
Fix typo
franksinankaya Aug 5, 2019
89ed468
Support proxies
franksinankaya Aug 6, 2019
8a4d808
Fix spacing
franksinankaya Aug 6, 2019
2124784
Move winhttppal to its own library
franksinankaya Sep 2, 2019
78ef46b
Delta
franksinankaya Sep 2, 2019
df34d8f
Share parse_headers_string
franksinankaya Sep 3, 2019
4332fe5
Implement auth scheme
franksinankaya Sep 3, 2019
fce2480
Remove http_client_winhttppal.cpp
franksinankaya Sep 3, 2019
17a75fc
sudo install
franksinankaya Sep 3, 2019
8db16da
Undo warning suppress
franksinankaya Sep 3, 2019
cdb2244
Fix capitalization
franksinankaya Sep 3, 2019
22b34f9
Merge remote-tracking branch 'origin/master' into frkaya/curlhttp
BillyONeal Sep 27, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Release/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ endif()

include(cmake/cpprest_find_boost.cmake)
include(cmake/cpprest_find_zlib.cmake)
include(cmake/cpprest_find_winhttppal.cmake)
include(cmake/cpprest_find_openssl.cmake)
include(cmake/cpprest_find_websocketpp.cmake)
include(cmake/cpprest_find_brotli.cmake)
Expand Down
17 changes: 17 additions & 0 deletions Release/cmake/cpprest_find_winhttppal.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function(cpprest_find_winhttppal)
if(TARGET cpprestsdk_winhttppal_internal)
return()
endif()

if(NOT WINHTTPPAL_LIBRARY OR NOT WINHTTPPAL_INCLUDE_DIRS)
find_package(winhttppal REQUIRED)
endif()

add_library(cpprestsdk_winhttppal_internal INTERFACE)
if(TARGET winhttppal::winhttppal)
target_link_libraries(cpprestsdk_winhttppal_internal INTERFACE winhttppal::winhttppal)
else()
target_link_libraries(cpprestsdk_winhttppal_internal INTERFACE "$<BUILD_INTERFACE:${WINHTTPPAL_LIBRARY}>")
target_include_directories(cpprestsdk_winhttppal_internal INTERFACE "$<BUILD_INTERFACE:${WINHTTPPAL_INCLUDE_DIRS}>")
endif()
endfunction()
4 changes: 4 additions & 0 deletions Release/cmake/cpprestsdk-config.in.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ if(@CPPREST_USES_OPENSSL@)
find_dependency(OpenSSL)
endif()

if(@CPPREST_USES_WINHTTPPAL@)
find_dependency(WINHTTPPAL)
endif()

if(@CPPREST_USES_BOOST@ AND OFF)
if(UNIX)
find_dependency(Boost COMPONENTS random system thread filesystem chrono atomic date_time regex)
Expand Down
8 changes: 4 additions & 4 deletions Release/include/cpprest/http_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class http_client_config
#if !defined(_WIN32) && !defined(__cplusplus_winrt) || defined(CPPREST_FORCE_HTTP_CLIENT_ASIO)
, m_tlsext_sni_enabled(true)
#endif
#if defined(_WIN32) && !defined(__cplusplus_winrt)
#if (defined(_WIN32) && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
, m_buffer_request(false)
#endif
{
Expand Down Expand Up @@ -262,7 +262,7 @@ class http_client_config
void set_validate_certificates(bool validate_certs) { m_validate_certificates = validate_certs; }
#endif

#if defined(_WIN32) && !defined(__cplusplus_winrt)
#if (defined(_WIN32) && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
/// <summary>
/// Checks if request data buffering is turned on, the default is off.
/// </summary>
Expand Down Expand Up @@ -389,7 +389,7 @@ class http_client_config
std::function<void(boost::asio::ssl::context&)> m_ssl_context_callback;
bool m_tlsext_sni_enabled;
#endif
#if defined(_WIN32) && !defined(__cplusplus_winrt)
#if (defined(_WIN32) && !defined(__cplusplus_winrt)) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
bool m_buffer_request;
#endif
};
Expand Down Expand Up @@ -716,7 +716,7 @@ class http_client

namespace details
{
#if defined(_WIN32)
#if defined(_WIN32) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
extern const utility::char_t* get_with_body_err_msg;
#endif

Expand Down
12 changes: 12 additions & 0 deletions Release/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ if(CPPREST_HTTP_CLIENT_IMPL STREQUAL "asio")
target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_HTTP_CLIENT_ASIO)
target_sources(cpprest PRIVATE http/client/http_client_asio.cpp http/client/x509_cert_utilities.cpp)
target_link_libraries(cpprest PUBLIC cpprestsdk_boost_internal cpprestsdk_openssl_internal)
elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winhttppal")
cpprest_find_boost()
franksinankaya marked this conversation as resolved.
Show resolved Hide resolved
cpprest_find_openssl()
cpprest_find_winhttppal()
target_compile_definitions(cpprest PUBLIC -DCPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
target_sources(cpprest PRIVATE http/client/http_client_winhttp.cpp http/client/x509_cert_utilities.cpp)
target_link_libraries(cpprest PUBLIC cpprestsdk_boost_internal cpprestsdk_openssl_internal cpprestsdk_winhttppal_internal)
elseif(CPPREST_HTTP_CLIENT_IMPL STREQUAL "winhttp")
target_link_libraries(cpprest PRIVATE
httpapi.lib
Expand Down Expand Up @@ -237,6 +244,7 @@ if(CPPREST_INSTALL)
set(CPPREST_USES_ZLIB OFF)
set(CPPREST_USES_BROTLI OFF)
set(CPPREST_USES_OPENSSL OFF)
set(CPPREST_USES_WINHTTPPAL OFF)

set(CPPREST_TARGETS cpprest)
if(TARGET cpprestsdk_boost_internal)
Expand All @@ -255,6 +263,10 @@ if(CPPREST_INSTALL)
list(APPEND CPPREST_TARGETS cpprestsdk_openssl_internal)
set(CPPREST_USES_OPENSSL ON)
endif()
if(TARGET cpprestsdk_winhttppal_internal)
list(APPEND CPPREST_TARGETS cpprestsdk_winhttppal_internal)
set(CPPREST_USES_WINHTTPPAL ON)
endif()
if(TARGET cpprestsdk_websocketpp_internal)
list(APPEND CPPREST_TARGETS cpprestsdk_websocketpp_internal)
endif()
Expand Down
4 changes: 2 additions & 2 deletions Release/src/http/client/http_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ static void verify_uri(const uri& uri)

namespace details
{
#if defined(_WIN32)
extern const utility::char_t* get_with_body_err_msg =
#if defined(_WIN32) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
const utility::char_t* get_with_body_err_msg =
_XPLATSTR("A GET or HEAD request should not have an entity body.");
#endif

Expand Down
5 changes: 1 addition & 4 deletions Release/src/http/client/http_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,10 @@ namespace details
/// Serialize the http_headers into name:value pairs separated by a carriage return and line feed.
/// </summary>
utility::string_t flatten_http_headers(const http_headers& headers);
#if defined(_WIN32)
/// <summary>
/// Parses a string containing Http headers.
/// </summary>
void parse_headers_string(_Inout_z_ utf16char* headersStr, http_headers& headers);
#endif

void parse_headers_string(_Inout_z_ utility::char_t* headersStr, http_headers& headers);
} // namespace details
} // namespace http
} // namespace web
Expand Down
68 changes: 45 additions & 23 deletions Release/src/http/client/http_client_winhttp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@
#include "../common/internal_http_helpers.h"
#include "cpprest/http_headers.h"
#include "http_client_impl.h"
#ifdef WIN32
#include <Wincrypt.h>
#endif
#if defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
#include "winhttppal.h"
#endif
#include <atomic>

#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
#if _WIN32_WINNT && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
#include <VersionHelpers.h>
#endif

Expand Down Expand Up @@ -97,7 +102,7 @@ static http::status_code parse_status_code(HINTERNET request_handle)
&buffer[0],
&length,
WINHTTP_NO_HEADER_INDEX);
return (unsigned short)_wtoi(buffer.c_str());
return (unsigned short)stoi(buffer);
}

// Helper function to get the reason phrase from a WinHTTP response.
Expand All @@ -122,7 +127,7 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle)
/// <summary>
/// Parses a string containing HTTP headers.
/// </summary>
static void parse_winhttp_headers(HINTERNET request_handle, _In_z_ utf16char* headersStr, http_response& response)
static void parse_winhttp_headers(HINTERNET request_handle, _In_z_ utility::char_t* headersStr, http_response& response)
{
// Clear the header map for each new response; otherwise, the header values will be combined.
response.headers().clear();
Expand All @@ -141,7 +146,7 @@ static std::string build_error_msg(unsigned long code, const std::string& locati
msg.append(": ");
msg.append(std::to_string(code));
msg.append(": ");
msg.append(utility::details::windows_category().message(code));
msg.append(utility::details::platform_category().message(static_cast<int>(code)));
return msg;
}

Expand All @@ -159,6 +164,7 @@ static std::string build_error_msg(_In_ WINHTTP_ASYNC_RESULT* error_result)
}
}


class memory_holder
{
uint8_t* m_externalData;
Expand Down Expand Up @@ -289,7 +295,7 @@ class winhttp_request_context final : public request_context
{
}

#if defined(_MSC_VER) && _MSC_VER < 1900
#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
compression_state(const compression_state&) = delete;
compression_state(compression_state&& other)
: m_buffer(std::move(other.m_buffer))
Expand Down Expand Up @@ -552,6 +558,10 @@ class winhttp_request_context final : public request_context

void on_send_request_validate_cn()
{
#if defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
// we do the validation inside curl
return;
#else
if (m_customCnCheck.empty())
{
// no custom validation selected; either we've delegated that to winhttp or
Expand Down Expand Up @@ -647,6 +657,7 @@ class winhttp_request_context final : public request_context
}

m_cachedEncodedCert.assign(encodedFirst, encodedLast);
#endif
}

protected:
Expand All @@ -666,13 +677,13 @@ class winhttp_request_context final : public request_context
winhttp_request_context(const std::shared_ptr<_http_client_communicator>& client, const http_request& request)
: request_context(client, request)
, m_request_handle(nullptr)
, m_bodyType(no_body)
, m_startingPosition(std::char_traits<uint8_t>::eof())
, m_body_data()
, m_remaining_to_write(0)
, m_proxy_authentication_tried(false)
, m_server_authentication_tried(false)
, m_bodyType(no_body)
, m_remaining_to_write(0)
, m_startingPosition(std::char_traits<uint8_t>::eof())
, m_readStream(request.body())
, m_body_data()
{
}
};
Expand Down Expand Up @@ -731,10 +742,10 @@ class winhttp_client final : public _http_client_communicator
public:
winhttp_client(http::uri address, http_client_config client_config)
: _http_client_communicator(std::move(address), std::move(client_config))
, m_secure(m_uri.scheme() == _XPLATSTR("https"))
, m_opened(false)
, m_hSession(nullptr)
, m_hConnection(nullptr)
, m_secure(m_uri.scheme() == _XPLATSTR("https"))
{
}

Expand All @@ -752,7 +763,7 @@ class winhttp_client final : public _http_client_communicator
if (m_hSession != nullptr)
{
// Unregister the callback.
WinHttpSetStatusCallback(m_hSession, nullptr, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL);
WinHttpSetStatusCallback(m_hSession, nullptr, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0);

WinHttpCloseHandle(m_hSession);
}
Expand Down Expand Up @@ -792,8 +803,8 @@ class winhttp_client final : public _http_client_communicator
ie_proxy_config proxyIE;

DWORD access_type;
LPCWSTR proxy_name = WINHTTP_NO_PROXY_NAME;
LPCWSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS;
LPCTSTR proxy_name = WINHTTP_NO_PROXY_NAME;
LPCTSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS;
m_proxy_auto_config = false;
utility::string_t proxy_str;
http::uri uri;
Expand Down Expand Up @@ -901,7 +912,7 @@ class winhttp_client final : public _http_client_communicator
}

// Enable TLS 1.1 and 1.2
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA) || defined(CPPREST_FORCE_HTTP_CLIENT_WINHTTPPAL)
BOOL win32_result(FALSE);

DWORD secure_protocols(WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
Expand Down Expand Up @@ -965,6 +976,17 @@ class winhttp_client final : public _http_client_communicator
proxy_info info;
bool proxy_info_required = false;

const auto& method = msg.method();

// stop injection of headers via method
// resource should be ok, since it's been encoded
// and host won't resolve
if (!::web::http::details::validate_method(method))
{
request->report_exception(http_exception("The method string is invalid."));
return;
}

if (m_proxy_auto_config)
{
WINHTTP_AUTOPROXY_OPTIONS autoproxy_options {};
Expand Down Expand Up @@ -1416,7 +1438,6 @@ class winhttp_client final : public _http_client_communicator
{
return pplx::task_from_exception<size_t>(std::current_exception());
}
_ASSERTE(bytes_read >= 0);

uint8_t* buffer = p_request_context->m_compression_state.m_acquired;
if (buffer == nullptr)
Expand Down Expand Up @@ -1689,16 +1710,16 @@ class winhttp_client final : public _http_client_communicator
}
}

static std::wstring get_request_url(HINTERNET hRequestHandle)
static utility::string_t get_request_url(HINTERNET hRequestHandle)
{
std::wstring url;
utility::string_t url;
auto urlSize = static_cast<unsigned long>(url.capacity()) * 2; // use initial small string optimization capacity
for (;;)
{
url.resize(urlSize / sizeof(wchar_t));
if (WinHttpQueryOption(hRequestHandle, WINHTTP_OPTION_URL, &url[0], &urlSize))
url.resize(urlSize / sizeof(utility::char_t));
if (WinHttpQueryOption(hRequestHandle, WINHTTP_OPTION_URL, &url[0], (LPDWORD)&urlSize))
{
url.resize(wcslen(url.c_str()));
url.resize(url.length());
return url;
}

Expand Down Expand Up @@ -2014,7 +2035,7 @@ class winhttp_client final : public _http_client_communicator
// Now allocate buffer for headers and query for them.
std::vector<unsigned char> header_raw_buffer;
header_raw_buffer.resize(headerBufferLength);
utf16char* header_buffer = reinterpret_cast<utf16char*>(&header_raw_buffer[0]);
utility::char_t* header_buffer = reinterpret_cast<utility::char_t*>(&header_raw_buffer[0]);
if (!WinHttpQueryHeaders(hRequestHandle,
WINHTTP_QUERY_RAW_HEADERS_CRLF,
WINHTTP_HEADER_NAME_BY_INDEX,
Expand Down Expand Up @@ -2052,7 +2073,7 @@ class winhttp_client final : public _http_client_communicator
!p_request_context->m_http_client->client_config().request_compressed_response())
{
p_request_context->m_compression_state.m_chunk =
std::make_unique<winhttp_request_context::compression_state::_chunk_helper>();
::utility::details::make_unique<winhttp_request_context::compression_state::_chunk_helper>();
p_request_context->m_compression_state.m_chunked = true;
}

Expand Down Expand Up @@ -2390,7 +2411,7 @@ class winhttp_client final : public _http_client_communicator
}).then([p_request_context](pplx::task<bool> op) {
try
{
bool ignored = op.get();
op.get();
}
catch (...)
{
Expand Down Expand Up @@ -2466,6 +2487,7 @@ std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage(
return std::make_shared<details::winhttp_client>(std::move(base_uri), std::move(client_config));
}


} // namespace details
} // namespace client
} // namespace http
Expand Down
20 changes: 10 additions & 10 deletions Release/src/http/common/http_msg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,27 +225,27 @@ utility::string_t flatten_http_headers(const http_headers& headers)
return flattened_headers;
}

#if defined(_WIN32)
void parse_headers_string(_Inout_z_ utf16char* headersStr, http_headers& headers)
void parse_headers_string(_Inout_z_ utility::char_t* headersStr, web::http::http_headers& headers)
{
utf16char* context = nullptr;
utf16char* line = wcstok_s(headersStr, CRLF, &context);
while (line != nullptr)
utility::string_t str(headersStr);
std::size_t pos = str.find_first_of(_XPLATSTR("\r\n"));
std::size_t startpos = 0;
while (pos!=std::string::npos)
{
const utility::string_t header_line(line);
const utility::string_t header_line(str, startpos, pos - startpos);
const size_t colonIndex = header_line.find_first_of(_XPLATSTR(":"));
if (colonIndex != utility::string_t::npos)
{
utility::string_t key = header_line.substr(0, colonIndex);
utility::string_t value = header_line.substr(colonIndex + 1, header_line.length() - colonIndex - 1);
http::details::trim_whitespace(key);
http::details::trim_whitespace(value);
web::http::details::trim_whitespace(key);
web::http::details::trim_whitespace(value);
headers.add(key, value);
}
line = wcstok_s(nullptr, CRLF, &context);
startpos = pos + 1;
pos = str.find_first_of(_XPLATSTR("\r\n"), pos + 1);
}
}
#endif

} // namespace details

Expand Down
Loading