Skip to content

Commit 7ab08d4

Browse files
committed
Potential solution to avoid cpprestsdk patch
1 parent ea35028 commit 7ab08d4

File tree

2 files changed

+91
-29
lines changed

2 files changed

+91
-29
lines changed

src/AppInstallerCommonCore/HttpClientHelper.cpp

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,29 @@
99

1010
namespace AppInstaller::Http
1111
{
12+
namespace details
13+
{
14+
void InvocationContext::CaptureRequestContext(web::http::client::native_handle handle)
15+
{
16+
HINTERNET requestHandle = reinterpret_cast<HINTERNET>(handle);
17+
std::weak_ptr<void>* contextValue = nullptr;
18+
DWORD valueSize = sizeof(contextValue);
19+
20+
if (LOG_IF_WIN32_BOOL_FALSE(WinHttpQueryOption(requestHandle, WINHTTP_OPTION_CONTEXT_VALUE, &contextValue, &valueSize)))
21+
{
22+
if (contextValue && valueSize == sizeof(contextValue))
23+
{
24+
std::shared_ptr<void> lockedContextValue = contextValue->lock();
25+
if (lockedContextValue)
26+
{
27+
RequestHandle = requestHandle;
28+
RequestContextLifetime = std::move(lockedContextValue);
29+
}
30+
}
31+
}
32+
}
33+
}
34+
1235
namespace
1336
{
1437
// If the caller does not pass in a user agent header, put the default one on the request.
@@ -25,6 +48,7 @@ namespace AppInstaller::Http
2548
void NativeHandleServerCertificateValidation(web::http::client::native_handle handle, const Certificates::PinningConfiguration& pinningConfiguration)
2649
{
2750
HINTERNET requestHandle = reinterpret_cast<HINTERNET>(handle);
51+
THROW_HR_IF(E_POINTER, requestHandle == NULL || requestHandle == INVALID_HANDLE_VALUE);
2852

2953
// Get certificate and pass along to pinning config
3054
wil::unique_cert_context certContext;
@@ -44,6 +68,33 @@ namespace AppInstaller::Http
4468

4569
return 0s;
4670
}
71+
72+
details::InvocationContext GetClient(
73+
const utility::string_t& uri,
74+
web::http::client::http_client_config clientConfig,
75+
const std::shared_ptr<web::http::http_pipeline_stage>& defaultRequestHandlerStage,
76+
bool captureRequestContext)
77+
{
78+
details::InvocationContext result;
79+
80+
if (captureRequestContext)
81+
{
82+
clientConfig.set_nativehandle_options([&result](web::http::client::native_handle handle)
83+
{
84+
result.CaptureRequestContext(handle);
85+
});
86+
}
87+
88+
result.HttpClient = std::make_unique<web::http::client::http_client>(uri, clientConfig);
89+
90+
// Add default custom handlers if any.
91+
if (defaultRequestHandlerStage)
92+
{
93+
result.HttpClient->add_handler(defaultRequestHandlerStage);
94+
}
95+
96+
return result;
97+
}
4798
}
4899

49100
HttpClientHelper::HttpClientHelper(std::shared_ptr<web::http::http_pipeline_stage> stage)
@@ -61,14 +112,14 @@ namespace AppInstaller::Http
61112
}
62113
}
63114

64-
pplx::task<web::http::http_response> HttpClientHelper::Post(
115+
details::InvocationContext HttpClientHelper::Post(
65116
const utility::string_t& uri,
66117
const web::json::value& body,
67118
const HttpClientHelper::HttpRequestHeaders& headers,
68119
const HttpClientHelper::HttpRequestHeaders& authHeaders) const
69120
{
70121
AICLI_LOG(Repo, Info, << "Sending http POST request to: " << utility::conversions::to_utf8string(uri));
71-
web::http::client::http_client client = GetClient(uri);
122+
details::InvocationContext result = GetClient(uri, m_clientConfig, m_defaultRequestHandlerStage, m_pinningConfiguration.has_value());
72123
web::http::http_request request{ web::http::methods::POST };
73124
request.headers().set_content_type(web::http::details::mime_types::application_json);
74125
request.set_body(body.serialize());
@@ -88,7 +139,8 @@ namespace AppInstaller::Http
88139
request.headers().add(pair.first, pair.second);
89140
}
90141

91-
return client.request(request);
142+
result.ResponseTask = result.HttpClient->request(request);
143+
return result;
92144
}
93145

94146
std::optional<web::json::value> HttpClientHelper::HandlePost(
@@ -99,11 +151,17 @@ namespace AppInstaller::Http
99151
const HttpResponseHandler& customHandler) const try
100152
{
101153
web::http::http_response httpResponse;
102-
Post(uri, body, headers, authHeaders).then([&httpResponse](const web::http::http_response& response)
154+
details::InvocationContext context = Post(uri, body, headers, authHeaders);
155+
context.ResponseTask.then([&httpResponse](const web::http::http_response& response)
103156
{
104157
httpResponse = response;
105158
}).wait();
106159

160+
if (m_pinningConfiguration)
161+
{
162+
NativeHandleServerCertificateValidation(context.RequestHandle, m_pinningConfiguration.value());
163+
}
164+
107165
if (customHandler)
108166
{
109167
auto handlerResult = customHandler(httpResponse);
@@ -120,13 +178,13 @@ namespace AppInstaller::Http
120178
RethrowAsWilException(exception);
121179
}
122180

123-
pplx::task<web::http::http_response> HttpClientHelper::Get(
181+
details::InvocationContext HttpClientHelper::Get(
124182
const utility::string_t& uri,
125183
const HttpClientHelper::HttpRequestHeaders& headers,
126184
const HttpClientHelper::HttpRequestHeaders& authHeaders) const
127185
{
128186
AICLI_LOG(Repo, Info, << "Sending http GET request to: " << utility::conversions::to_utf8string(uri));
129-
web::http::client::http_client client = GetClient(uri);
187+
details::InvocationContext result = GetClient(uri, m_clientConfig, m_defaultRequestHandlerStage, m_pinningConfiguration.has_value());
130188
web::http::http_request request{ web::http::methods::GET };
131189
request.headers().set_content_type(web::http::details::mime_types::application_json);
132190

@@ -145,7 +203,8 @@ namespace AppInstaller::Http
145203
request.headers().add(pair.first, pair.second);
146204
}
147205

148-
return client.request(request);
206+
result.ResponseTask = result.HttpClient->request(request);
207+
return result;
149208
}
150209

151210
std::optional<web::json::value> HttpClientHelper::HandleGet(
@@ -155,11 +214,17 @@ namespace AppInstaller::Http
155214
const HttpResponseHandler& customHandler) const try
156215
{
157216
web::http::http_response httpResponse;
158-
Get(uri, headers, authHeaders).then([&httpResponse](const web::http::http_response& response)
217+
details::InvocationContext context = Get(uri, headers, authHeaders);
218+
context.ResponseTask.then([&httpResponse](const web::http::http_response& response)
159219
{
160220
httpResponse = response;
161221
}).wait();
162222

223+
if (m_pinningConfiguration)
224+
{
225+
NativeHandleServerCertificateValidation(context.RequestHandle, m_pinningConfiguration.value());
226+
}
227+
163228
if (customHandler)
164229
{
165230
auto handlerResult = customHandler(httpResponse);
@@ -178,23 +243,7 @@ namespace AppInstaller::Http
178243

179244
void HttpClientHelper::SetPinningConfiguration(const Certificates::PinningConfiguration& configuration)
180245
{
181-
m_clientConfig.set_nativehandle_servercertificate_validation([pinConfig = configuration](web::http::client::native_handle handle)
182-
{
183-
NativeHandleServerCertificateValidation(handle, pinConfig);
184-
});
185-
}
186-
187-
web::http::client::http_client HttpClientHelper::GetClient(const utility::string_t& uri) const
188-
{
189-
web::http::client::http_client client{ uri, m_clientConfig };
190-
191-
// Add default custom handlers if any.
192-
if (m_defaultRequestHandlerStage)
193-
{
194-
client.add_handler(m_defaultRequestHandlerStage);
195-
}
196-
197-
return client;
246+
m_pinningConfiguration = configuration;
198247
}
199248

200249
std::optional<web::json::value> HttpClientHelper::ValidateAndExtractResponse(const web::http::http_response& response) const

src/AppInstallerCommonCore/Public/winget/HttpClientHelper.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,25 @@
44
#include <winget/Certificates.h>
55
#include <cpprest/http_client.h>
66
#include <cpprest/json.h>
7+
#include <memory>
78
#include <optional>
89
#include <vector>
910

1011
namespace AppInstaller::Http
1112
{
13+
namespace details
14+
{
15+
struct InvocationContext
16+
{
17+
std::unique_ptr<web::http::client::http_client> HttpClient;
18+
pplx::task<web::http::http_response> ResponseTask;
19+
web::http::client::native_handle RequestHandle = INVALID_HANDLE_VALUE;
20+
std::shared_ptr<void> RequestContextLifetime;
21+
22+
void CaptureRequestContext(web::http::client::native_handle handle);
23+
};
24+
}
25+
1226
struct HttpClientHelper
1327
{
1428
using HttpRequestHeaders = std::unordered_map<utility::string_t, utility::string_t>;
@@ -26,11 +40,11 @@ namespace AppInstaller::Http
2640

2741
HttpClientHelper(std::shared_ptr<web::http::http_pipeline_stage> = {});
2842

29-
pplx::task<web::http::http_response> Post(const utility::string_t& uri, const web::json::value& body, const HttpRequestHeaders& headers = {}, const HttpRequestHeaders& authHeaders = {}) const;
43+
details::InvocationContext Post(const utility::string_t& uri, const web::json::value& body, const HttpRequestHeaders& headers = {}, const HttpRequestHeaders& authHeaders = {}) const;
3044

3145
std::optional<web::json::value> HandlePost(const utility::string_t& uri, const web::json::value& body, const HttpRequestHeaders& headers = {}, const HttpRequestHeaders& authHeaders = {}, const HttpResponseHandler& customHandler = {}) const;
3246

33-
pplx::task<web::http::http_response> Get(const utility::string_t& uri, const HttpRequestHeaders& headers = {}, const HttpRequestHeaders& authHeaders = {}) const;
47+
details::InvocationContext Get(const utility::string_t& uri, const HttpRequestHeaders& headers = {}, const HttpRequestHeaders& authHeaders = {}) const;
3448

3549
std::optional<web::json::value> HandleGet(const utility::string_t& uri, const HttpRequestHeaders& headers = {}, const HttpRequestHeaders& authHeaders = {}, const HttpResponseHandler& customHandler = {}) const;
3650

@@ -42,12 +56,11 @@ namespace AppInstaller::Http
4256
std::optional<web::json::value> ExtractJsonResponse(const web::http::http_response& response) const;
4357

4458
private:
45-
web::http::client::http_client GetClient(const utility::string_t& uri) const;
46-
4759
// Translates a cpprestsdk http_exception to a WIL exception.
4860
static void RethrowAsWilException(const web::http::http_exception& exception);
4961

5062
std::shared_ptr<web::http::http_pipeline_stage> m_defaultRequestHandlerStage;
5163
web::http::client::http_client_config m_clientConfig;
64+
std::optional<Certificates::PinningConfiguration> m_pinningConfiguration;
5265
};
5366
}

0 commit comments

Comments
 (0)