99
1010namespace 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
0 commit comments