bool request::validate() { return validate_method() && validate_length() && find_and_validate_format(); }
// Start sending request. void send_request(_In_ const std::shared_ptr<request_context> &request) { http_request &msg = request->m_request; auto winrt_context = std::static_pointer_cast<winrt_request_context>(request); if (!validate_method(msg.method())) { request->report_exception(http_exception(L"The method string is invalid.")); return; } if (msg.method() == http::methods::TRCE) { // Not supported by WinInet. Generate a more specific exception than what WinInet does. request->report_exception(http_exception(L"TRACE is not supported")); return; } const size_t content_length = msg._get_impl()->_get_content_length(); if (content_length == std::numeric_limits<size_t>::max()) { // IXHR2 does not allow transfer encoding chunked. So the user is expected to set the content length request->report_exception(http_exception(L"Content length is not specified in the http headers")); return; } // Start sending HTTP request. HRESULT hr = CoCreateInstance( __uuidof(FreeThreadedXMLHTTP60), nullptr, CLSCTX_INPROC, __uuidof(IXMLHTTPRequest2), reinterpret_cast<void**>(winrt_context->m_hRequest.GetAddressOf())); if (FAILED(hr)) { request->report_error(hr, L"Failure to create IXMLHTTPRequest2 instance"); return; } utility::string_t encoded_resource = http::uri_builder(m_uri).append(msg.relative_uri()).to_string(); const auto &config = client_config(); const auto &client_cred = config.credentials(); const auto &proxy = config.proxy(); const auto &proxy_cred = proxy.credentials(); if (!proxy.is_default()) { request->report_exception(http_exception(L"Only a default proxy server is supported")); return; } // New scope to ensure plain text password is cleared as soon as possible. { utility::string_t username, proxy_username; const utility::char_t *password = nullptr; const utility::char_t *proxy_password = nullptr; ::web::details::plaintext_string password_plaintext, proxy_password_plaintext; if (client_cred.is_set()) { username = client_cred.username(); password_plaintext = client_cred.decrypt(); password = password_plaintext->c_str(); } if (proxy_cred.is_set()) { proxy_username = proxy_cred.username(); proxy_password_plaintext = proxy_cred.decrypt(); proxy_password = proxy_password_plaintext->c_str(); } hr = winrt_context->m_hRequest->Open( msg.method().c_str(), encoded_resource.c_str(), Make<HttpRequestCallback>(winrt_context).Get(), username.c_str(), password, proxy_username.c_str(), proxy_password); } if (FAILED(hr)) { request->report_error(hr, L"Failure to open HTTP request"); return; } // Suppress automatic prompts for user credentials, since they are already provided. hr = winrt_context->m_hRequest->SetProperty(XHR_PROP_NO_CRED_PROMPT, TRUE); if (FAILED(hr)) { request->report_error(hr, L"Failure to set no credentials prompt property"); return; } const auto timeout = config.timeout(); const int secs = static_cast<int>(timeout.count()); hr = winrt_context->m_hRequest->SetProperty(XHR_PROP_TIMEOUT, secs * 1000); if (FAILED(hr)) { request->report_error(hr, L"Failure to set HTTP request properties"); return; } // Add headers. for (const auto &hdr : msg.headers()) { winrt_context->m_hRequest->SetRequestHeader(hdr.first.c_str(), hdr.second.c_str()); } // Set response stream. hr = winrt_context->m_hRequest->SetCustomResponseStream(Make<IResponseStream>(request).Get()); if (FAILED(hr)) { request->report_error(hr, L"Failure to set HTTP response stream"); return; } // Call the callback function of user customized options try { config.call_user_nativehandle_options(winrt_context->m_hRequest.Get()); } catch (...) { request->report_exception(std::current_exception()); return; } if (content_length == 0) { hr = winrt_context->m_hRequest->Send(nullptr, 0); } else { if ( msg.method() == http::methods::GET || msg.method() == http::methods::HEAD ) { request->report_exception(http_exception(get_with_body)); return; } hr = winrt_context->m_hRequest->Send(Make<IRequestStream>(winrt_context, content_length).Get(), content_length); } if ( FAILED(hr) ) { request->report_error(hr, L"Failure to send HTTP request"); return; } // Register for notification on cancellation to abort this request. if(msg._cancellation_token() != pplx::cancellation_token::none()) { auto requestHandle = winrt_context->m_hRequest; // cancellation callback is unregistered when request is completed. winrt_context->m_cancellationRegistration = msg._cancellation_token().register_callback([requestHandle]() { requestHandle->Abort(); }); } }