Index: net/simple_request.cc |
diff --git a/net/simple_request.cc b/net/simple_request.cc |
deleted file mode 100644 |
index 9ae69b674727ac43c4c7bbed42c7cd1d2e07c341..0000000000000000000000000000000000000000 |
--- a/net/simple_request.cc |
+++ /dev/null |
@@ -1,798 +0,0 @@ |
-// Copyright 2007-2010 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
-// ======================================================================== |
- |
-// The implementation does not allow concurrent calls on the same object but |
-// it allows calling SimpleRequest::Cancel in order to stop an ongoing request. |
-// The transient state of the request is maintained by request_state_. |
-// The state is created by SimpleRequest::Send and it is destroyed by |
-// SimpleRequest::Close. The only concurrent access to the object state can |
-// happen during calling SimpleRequest::Cancel(), Pause() and Resume(). Cancel |
-// closes the connection and the request handles. This makes any of the WinHttp |
-// calls on these handles fail and SimpleRequest::Send return to the caller. |
-// Pause() also closes the handles but SimpleRequest automatically reopens |
-// them when Resume() is called. During resume stage, SimpleRequest sends a |
-// range request to continue download. During these actions, the caller is still |
-// blocked. |
- |
-#include "omaha/net/simple_request.h" |
-#include <atlconv.h> |
-#include <climits> |
-#include <memory> |
-#include <vector> |
-#include "omaha/base/const_addresses.h" |
-#include "omaha/base/constants.h" |
-#include "omaha/base/debug.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/logging.h" |
-#include "omaha/base/scoped_any.h" |
-#include "omaha/base/scope_guard.h" |
-#include "omaha/base/string.h" |
-#include "omaha/net/network_config.h" |
-#include "omaha/net/network_request.h" |
-#include "omaha/net/proxy_auth.h" |
-#include "omaha/net/winhttp_adapter.h" |
- |
-namespace omaha { |
- |
-SimpleRequest::SimpleRequest() |
- : request_buffer_(NULL), |
- request_buffer_length_(0), |
- proxy_auth_config_(NULL, CString()), |
- is_canceled_(false), |
- is_closed_(false), |
- session_handle_(NULL), |
- low_priority_(false), |
- callback_(NULL), |
- download_completed_(false), |
- pause_happened_(false) { |
- user_agent_.Format(_T("%s;winhttp"), NetworkConfig::GetUserAgent()); |
- |
- // Create a manual reset event to wait on during network transfer. |
- // The event is signaled by default meaning the network transferring is |
- // enabled. Pause() resets this event to stop network activity. Resume() |
- // does the opposite as Pause(). Close() and Cancel() also set the event. |
- // This unlocks the thread if it is in paused state and returns control |
- // to the caller. |
- reset(event_resume_, ::CreateEvent(NULL, true, true, NULL)); |
- ASSERT1(valid(event_resume_)); |
-} |
- |
-// TODO(omaha): we should attempt to cleanup the file only if we |
-// created it in the first place. |
-SimpleRequest::~SimpleRequest() { |
- Close(); |
- callback_ = NULL; |
- |
- // If download failed, try to clean up the target file. |
- if (!download_completed_ && !filename_.IsEmpty()) { |
- if (!::DeleteFile(filename_) && ::GetLastError() != ERROR_FILE_NOT_FOUND) { |
- NET_LOG(LW, (_T("[SimpleRequest][Failed to delete file: %s][0x%08x]."), |
- filename_.GetString(), HRESULTFromLastError())); |
- } |
- } |
-} |
- |
-void SimpleRequest::set_url(const CString& url) { |
- __mutexScope(lock_); |
- if (url_ != url) { |
- url_ = url; |
- CloseHandles(); |
- request_state_.reset(); |
- } |
-} |
- |
-void SimpleRequest::set_filename(const CString& filename) { |
- __mutexScope(lock_); |
- if (filename_ != filename) { |
- filename_ = filename; |
- CloseHandles(); |
- request_state_.reset(); |
- } |
-} |
- |
-HRESULT SimpleRequest::Close() { |
- NET_LOG(L3, (_T("[SimpleRequest::Close]"))); |
- |
- __mutexScope(lock_); |
- is_closed_ = true; |
- CloseHandles(); |
- request_state_.reset(); |
- winhttp_adapter_.reset(); |
- |
- // Resume the downloading thread if it is blocked. It is still fine if the |
- // event is set since the operation is like no-op in that case. |
- return Resume(); |
-} |
- |
-HRESULT SimpleRequest::Cancel() { |
- NET_LOG(L3, (_T("[SimpleRequest::Cancel]"))); |
- |
- __mutexScope(lock_); |
- is_canceled_ = true; |
- CloseHandles(); |
- |
- // Resume the downloading thread if it is blocked. It is still fine if the |
- // event is set since the operation is like no-op in that case. |
- return Resume(); |
-} |
- |
-void SimpleRequest::CloseHandles() { |
- if (winhttp_adapter_.get()) { |
- winhttp_adapter_->CloseHandles(); |
- } |
-} |
- |
-bool SimpleRequest::IsResumeNeeded() const { |
- __mutexScope(lock_); |
- if (!IsPauseSupported() || is_canceled_ || is_closed_) { |
- return false; |
- } |
- |
- return pause_happened_; |
-} |
- |
-bool SimpleRequest::IsPauseSupported() const { |
- __mutexScope(lock_); |
- return valid(event_resume_) && !IsPostRequest() && !filename_.IsEmpty(); |
-} |
- |
-HRESULT SimpleRequest::Pause() { |
- NET_LOG(L3, (_T("[SimpleRequest::Pause]"))); |
- |
- if (!IsPauseSupported()) { |
- return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); |
- } |
- |
- __mutexScope(ready_to_pause_lock_); |
- __mutexScope(lock_); |
- |
- pause_happened_ = true; |
- CloseHandles(); |
- return ::ResetEvent(get(event_resume_)) ? S_OK : HRESULTFromLastError(); |
-} |
- |
-HRESULT SimpleRequest::Resume() { |
- NET_LOG(L3, (_T("[SimpleRequest::Resume]"))); |
- |
- __mutexScope(lock_); |
- HRESULT hr = S_OK; |
- if (IsPauseSupported()) { |
- hr = ::SetEvent(get(event_resume_)) ? S_OK : HRESULTFromLastError(); |
- } |
- return hr; |
-} |
- |
-void SimpleRequest::WaitForResumeEvent() { |
- if (!event_resume_) { |
- return; |
- } |
- |
- // Reset pause_happened_ state to indicate that pause has not yet happened |
- // during new resume stage. |
- __mutexBlock(lock_) { |
- pause_happened_ = false; |
- } |
- |
- VERIFY1(::WaitForSingleObject(get(event_resume_), INFINITE) != WAIT_FAILED); |
-} |
- |
-HRESULT SimpleRequest::Send() { |
- NET_LOG(L3, (_T("[SimpleRequest::Send][%s]"), url_)); |
- |
- ASSERT1(!url_.IsEmpty()); |
- if (!session_handle_) { |
- NET_LOG(LE, (_T("[SimpleRequest: session_handle_ is NULL]"))); |
- return OMAHA_NET_E_WINHTTP_NOT_AVAILABLE; |
- } |
- |
- HRESULT hr = S_OK; |
- |
- __mutexBlock(ready_to_pause_lock_) { |
- __mutexBlock(lock_) { |
- winhttp_adapter_.reset(new WinHttpAdapter()); |
- hr = winhttp_adapter_->Initialize(); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- if (!IsPauseSupported() || request_state_ == NULL) { |
- request_state_.reset(new TransientRequestState); |
- } else { |
- // Discard all previous download states except content_length and |
- // current_bytes for resume purpose. These two states will be validated |
- // against the previously (partially) downloaded file when reopens the |
- // target file. |
- scoped_ptr<TransientRequestState> request_state( |
- new TransientRequestState); |
- request_state->content_length = request_state_->content_length; |
- request_state->current_bytes = request_state_->current_bytes; |
- |
- request_state_.swap(request_state); |
- } |
- } |
- } |
- |
- for (bool first_time = true, cancelled = false; |
- !cancelled; |
- first_time = false) { |
- scoped_hfile file_handle; |
- |
- __mutexBlock(ready_to_pause_lock_) { |
- if (!first_time) { |
- if (IsResumeNeeded()) { |
- NET_LOG(L3, (_T("[SimpleRequest::Send paused.]"))); |
- WaitForResumeEvent(); |
- NET_LOG(L3, (_T("[SimpleRequest::Send resumed.]"))); |
- } else { |
- if (is_canceled_) { |
- hr = GOOPDATE_E_CANCELLED; |
- |
- // Once cancelled, we should set downloaded bytes to 0 |
- request_state_->current_bytes = 0; |
- } |
- |
- // Macro __mutexBlock has a hidden loop built-in and thus one break |
- // is not enough to exit the loop. Uses a flag instead. |
- cancelled = true; |
- } |
- } |
- |
- if (!cancelled) { |
- hr = PrepareRequest(address(file_handle)); |
- } |
- } |
- |
- if (SUCCEEDED(hr) && !cancelled) { |
- ASSERT1(request_state_->current_bytes <= request_state_->content_length); |
- |
- // Only requests data if there is more data to download. |
- if (request_state_->content_length == 0 || |
- request_state_->current_bytes < request_state_->content_length) { |
- hr = RequestData(get(file_handle)); |
- } |
- } |
- } |
- |
- NET_LOG(L3, |
- (_T("[SimpleRequest::Send][0x%08x][%d]"), hr, GetHttpStatusCode())); |
- return hr; |
-} |
- |
-HRESULT SimpleRequest::Connect() { |
- HRESULT hr = winhttp_adapter_->CrackUrl(url_, |
- ICU_DECODE, |
- &request_state_->scheme, |
- &request_state_->server, |
- &request_state_->port, |
- &request_state_->url_path, |
- NULL); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- ASSERT1(!request_state_->scheme.CompareNoCase(kHttpProtoScheme) || |
- !request_state_->scheme.CompareNoCase(kHttpsProtoScheme)); |
- |
- hr = winhttp_adapter_->Connect(session_handle_, |
- request_state_->server, |
- request_state_->port); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- // TODO(omaha): figure out the accept types. |
- // figure out more flags. |
- request_state_->is_https = false; |
- DWORD flags = WINHTTP_FLAG_REFRESH; |
- if (request_state_->scheme == kHttpsProtoScheme) { |
- request_state_->is_https = true; |
- flags |= WINHTTP_FLAG_SECURE; |
- } |
- const TCHAR* verb = IsPostRequest() ? _T("POST") : _T("GET"); |
- hr = winhttp_adapter_->OpenRequest(verb, request_state_->url_path, |
- NULL, WINHTTP_NO_REFERER, |
- WINHTTP_DEFAULT_ACCEPT_TYPES, flags); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- // Disable redirects for POST requests. |
- if (IsPostRequest()) { |
- VERIFY1(SUCCEEDED( |
- winhttp_adapter_->SetRequestOptionInt(WINHTTP_OPTION_DISABLE_FEATURE, |
- WINHTTP_DISABLE_REDIRECTS))); |
- } |
- |
- CString additional_headers = additional_headers_; |
- |
- // If the target has been partially downloaded, send a range request to resume |
- // download, instead of starting from scratch again. |
- if (request_state_->current_bytes != 0 && |
- request_state_->current_bytes != request_state_->content_length) { |
- ASSERT1(request_state_->current_bytes < request_state_->content_length); |
- additional_headers.AppendFormat(_T("Range: bytes=%d-\r\n"), |
- request_state_->current_bytes); |
- } |
- if (!additional_headers.IsEmpty()) { |
- uint32 header_flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE; |
- hr = winhttp_adapter_->AddRequestHeaders(additional_headers, |
- -1, |
- header_flags); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- } |
- |
- // If the WPAD detection fails, allow the request to go direct connection. |
- SetProxyInformation(); |
- |
- return S_OK; |
-} |
- |
-HRESULT SimpleRequest::OpenDestinationFile(HANDLE* file_handle) { |
- ASSERT1(!filename_.IsEmpty()); |
- ASSERT1(file_handle); |
- |
- DWORD create_disposition = request_state_->content_length == 0 ? |
- CREATE_ALWAYS : OPEN_ALWAYS; |
- |
- scoped_hfile file(::CreateFile(filename_, GENERIC_WRITE, 0, NULL, |
- create_disposition, FILE_ATTRIBUTE_NORMAL, |
- NULL)); |
- |
- if (!file) { |
- return HRESULTFromLastError(); |
- } |
- |
- if (request_state_->content_length != 0) { |
- DWORD raw_file_size = ::GetFileSize(get(file), NULL); |
- if (INVALID_FILE_SIZE == raw_file_size || raw_file_size > INT_MAX) { |
- return E_FAIL; |
- } |
- int file_size = static_cast<int>(raw_file_size); |
- |
- // Local file size should not be greater than remote file size and file |
- // size must match the number of bytes we previously downloaded. If not, |
- // reset the local file. |
- bool need_reset_file = file_size > request_state_->content_length; |
- need_reset_file |= file_size != request_state_->current_bytes; |
- |
- if (need_reset_file) { |
- // Need to download from byte 0. Reopen the file with truncation. |
- request_state_->current_bytes = 0; |
- reset(file, ::CreateFile(filename_, GENERIC_WRITE, 0, NULL, |
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); |
- |
- if (!file) { |
- return HRESULTFromLastError(); |
- } |
- } else { |
- LARGE_INTEGER start_pos; |
- start_pos.LowPart = static_cast<DWORD>(request_state_->current_bytes); |
- start_pos.HighPart = 0; |
- if (!::SetFilePointerEx(get(file), start_pos, NULL, FILE_BEGIN)) { |
- return HRESULTFromLastError(); |
- } |
- } |
- } else { |
- // Always start from byte 0 if we don't know remote file size. |
- request_state_->current_bytes = 0; |
- } |
- |
- *file_handle = release(file); |
- return S_OK; |
-} |
- |
-HRESULT SimpleRequest::SendRequest() { |
- int proxy_retry_count = 0; |
- int max_proxy_retries = 1; |
- CString username; |
- CString password; |
- HRESULT hr = S_OK; |
- |
- bool done = false; |
- while (!done) { |
- uint32& request_scheme = request_state_->proxy_authentication_scheme; |
- if (request_scheme) { |
- NET_LOG(L3, (_T("[SimpleRequest::SendRequest][auth_scheme][%d]"), |
- request_scheme)); |
- winhttp_adapter_->SetCredentials(WINHTTP_AUTH_TARGET_PROXY, |
- request_scheme, |
- username, password); |
- |
- CString headers; |
- headers.Format(_T("%s: %d\r\n"), |
- kHeaderXProxyRetryCount, proxy_retry_count); |
- if (!username.IsEmpty()) { |
- headers.AppendFormat(_T("%s: 1\r\n"), kHeaderXProxyManualAuth); |
- } |
- uint32 flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE; |
- VERIFY1(SUCCEEDED(winhttp_adapter_->AddRequestHeaders(headers, |
- -1, |
- flags))); |
- } |
- |
- size_t bytes_to_send = request_buffer_length_; |
- hr = winhttp_adapter_->SendRequest(NULL, |
- 0, |
- request_buffer_, |
- bytes_to_send, |
- bytes_to_send); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- NET_LOG(L3, |
- (_T("[SimpleRequest::SendRequest][request sent][server: %s][IP: %s]"), |
- winhttp_adapter_->server_name(), |
- winhttp_adapter_->server_ip())); |
- |
- hr = winhttp_adapter_->ReceiveResponse(); |
-#if DEBUG |
- LogResponseHeaders(); |
-#endif |
- if (hr == ERROR_WINHTTP_RESEND_REQUEST) { |
- // Resend the request if needed, likely because the authentication |
- // scheme requires many transactions on the same handle. |
- continue; |
- } else if (FAILED(hr)) { |
- return hr; |
- } |
- |
- hr = winhttp_adapter_->QueryRequestHeadersInt( |
- WINHTTP_QUERY_STATUS_CODE, |
- NULL, |
- &request_state_->http_status_code, |
- NULL); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- if (request_state_->http_status_code < HTTP_STATUS_FIRST || |
- request_state_->http_status_code > HTTP_STATUS_LAST) { |
- return E_FAIL; |
- } |
- |
- NetworkConfigManager& network_manager = NetworkConfigManager::Instance(); |
- switch (request_state_->http_status_code) { |
- case HTTP_STATUS_DENIED: |
- // 401 responses are not supported. Omaha does not have to authenticate |
- // to our backend. |
- done = true; |
- break; |
- |
- case HTTP_STATUS_PROXY_AUTH_REQ: { |
- NET_LOG(L2, (_T("[http proxy requires authentication]"))); |
- ++proxy_retry_count; |
- if (proxy_retry_count > max_proxy_retries) { |
- // If we get multiple 407s in a row then we are done. It does not make |
- // sense to retry further. |
- done = true; |
- break; |
- } |
- if (!request_scheme) { |
- uint32 supported_schemes(0), first_scheme(0), auth_target(0); |
- hr = winhttp_adapter_->QueryAuthSchemes(&supported_schemes, |
- &first_scheme, |
- &auth_target); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- ASSERT1(auth_target == WINHTTP_AUTH_TARGET_PROXY); |
- request_scheme = ChooseProxyAuthScheme(supported_schemes); |
- ASSERT1(request_scheme); |
- NET_LOG(L3, (_T("[SimpleRequest::SendRequest][Auth scheme][%d]"), |
- request_scheme)); |
- if (request_scheme == WINHTTP_AUTH_SCHEME_NEGOTIATE || |
- request_scheme == WINHTTP_AUTH_SCHEME_NTLM) { |
- // Increases the retry count. Tries to do an autologon at first, and |
- // if that fails, will call GetProxyCredentials below. |
- ++max_proxy_retries; |
- break; |
- } |
- } |
- |
- uint32 auth_scheme = UNKNOWN_AUTH_SCHEME; |
- // May prompt the user for credentials, or get cached credentials. |
- NetworkConfig* network_config = NULL; |
- hr = network_manager.GetUserNetworkConfig(&network_config); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- if (!network_config->GetProxyCredentials(true, |
- false, |
- request_state_->proxy, |
- proxy_auth_config_, |
- request_state_->is_https, |
- &username, |
- &password, |
- &auth_scheme)) { |
- NET_LOG(LE, |
- (_T("[SimpleRequest::SendRequest][GetProxyCreds failed]"))); |
- done = true; |
- break; |
- } |
- if (auth_scheme != UNKNOWN_AUTH_SCHEME) { |
- // Uses the known scheme that was successful previously. |
- request_scheme = auth_scheme; |
- } |
- break; |
- } |
- |
- default: |
- // We got some kind of response. If we have a valid username, we |
- // record the auth scheme with the NetworkConfig, so it can be cached |
- // for future use within this process for current user.. |
- if (!username.IsEmpty()) { |
- NetworkConfig* network_config = NULL; |
- hr = network_manager.GetUserNetworkConfig(&network_config); |
- if (SUCCEEDED(hr)) { |
- VERIFY1(SUCCEEDED(network_config->SetProxyAuthScheme( |
- request_state_->proxy, request_state_->is_https, |
- request_scheme))); |
- } |
- } |
- done = true; |
- break; |
- } |
- } |
- |
- return hr; |
-} |
- |
-HRESULT SimpleRequest::ReceiveData(HANDLE file_handle) { |
- ASSERT1(file_handle != INVALID_HANDLE_VALUE || filename_.IsEmpty()); |
- |
- HRESULT hr = S_OK; |
- |
- // In the case of a "204 No Content" response, WinHttp blocks when |
- // querying or reading the available data. According to the RFC, |
- // the 204 response must not include a message-body, and thus is always |
- // terminated by the first empty line after the header fields. |
- // It appears WinHttp does not internally handles the 204 response. If this, |
- // condition is not handled here explicitly, WinHttp will timeout when |
- // waiting for the data instead of returning right away. |
- if (request_state_->http_status_code == HTTP_STATUS_NO_CONTENT) { |
- return S_OK; |
- } |
- |
- int content_length = 0; |
- winhttp_adapter_->QueryRequestHeadersInt(WINHTTP_QUERY_CONTENT_LENGTH, |
- WINHTTP_HEADER_NAME_BY_INDEX, |
- &content_length, |
- WINHTTP_NO_HEADER_INDEX); |
- if (request_state_->content_length == 0) { |
- request_state_->content_length = content_length; |
- request_state_->current_bytes = 0; |
- } |
- |
- const bool is_http_success = |
- request_state_->http_status_code == HTTP_STATUS_OK || |
- request_state_->http_status_code == HTTP_STATUS_PARTIAL_CONTENT; |
- |
- std::vector<uint8> buffer; |
- do { |
- DWORD bytes_available(0); |
- winhttp_adapter_->QueryDataAvailable(&bytes_available); |
- buffer.resize(1 + bytes_available); |
- hr = winhttp_adapter_->ReadData(&buffer.front(), |
- buffer.size(), |
- &bytes_available); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- buffer.resize(bytes_available); |
- if (!buffer.empty()) { |
- if (!filename_.IsEmpty()) { |
- DWORD num_bytes(0); |
- if (!::WriteFile(file_handle, |
- reinterpret_cast<const char*>(&buffer.front()), |
- buffer.size(), &num_bytes, NULL)) { |
- return HRESULTFromLastError(); |
- } |
- ASSERT1(num_bytes == buffer.size()); |
- } else { |
- request_state_->response.insert(request_state_->response.end(), |
- buffer.begin(), |
- buffer.end()); |
- } |
- } |
- |
- // Update current_bytes after those bytes are serialized in case we |
- // pause before current_bytes is updated, we can throw away the last |
- // batch of bytes received and resume. |
- request_state_->current_bytes += bytes_available; |
- if (request_state_->content_length) { |
- ASSERT1(request_state_->current_bytes <= request_state_->content_length); |
- } |
- |
- // The callback is called only for 200 or 206 http codes. |
- if (callback_ && request_state_->content_length && is_http_success) { |
- callback_->OnProgress(request_state_->current_bytes, |
- request_state_->content_length, |
- WINHTTP_CALLBACK_STATUS_READ_COMPLETE, |
- NULL); |
- } |
- } while (!buffer.empty()); |
- |
- NET_LOG(L3, (_T("[bytes downloaded %d]"), request_state_->current_bytes)); |
- if (file_handle != INVALID_HANDLE_VALUE) { |
- // All bytes must be written to the file in the file download case. |
- ASSERT1(::SetFilePointer(file_handle, 0, NULL, FILE_CURRENT) == |
- static_cast<DWORD>(request_state_->current_bytes)); |
- } |
- |
- download_completed_ = true; |
- return hr; |
-} |
- |
-HRESULT SimpleRequest::PrepareRequest(HANDLE* file_handle) { |
- // Read the remaining bytes of the body. If we have a file to save the |
- // response into, create the file. |
- HRESULT hr = S_OK; |
- if (!filename_.IsEmpty()) { |
- hr = OpenDestinationFile(file_handle); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- } else { |
- // Always restarts if downloading to memory. |
- request_state_->current_bytes = 0; |
- request_state_->response.clear(); |
- } |
- |
- return Connect(); |
-} |
- |
-HRESULT SimpleRequest::RequestData(HANDLE file_handle) { |
- HRESULT hr = SendRequest(); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- return ReceiveData(file_handle); |
-} |
- |
-std::vector<uint8> SimpleRequest::GetResponse() const { |
- return request_state_.get() ? request_state_->response : |
- std::vector<uint8>(); |
-} |
- |
-HRESULT SimpleRequest::QueryHeadersString(uint32 info_level, |
- const TCHAR* name, |
- CString* value) const { |
- // Name can be null when the info_level specifies the header to query. |
- if (winhttp_adapter_.get()) { |
- return winhttp_adapter_->QueryRequestHeadersString(info_level, |
- name, |
- value, |
- WINHTTP_NO_HEADER_INDEX); |
- } else { |
- return E_UNEXPECTED; |
- } |
-} |
- |
-CString SimpleRequest::GetResponseHeaders() const { |
- CString response_headers; |
- if (winhttp_adapter_.get()) { |
- CString response_headers; |
- if (SUCCEEDED(winhttp_adapter_->QueryRequestHeadersString( |
- WINHTTP_QUERY_RAW_HEADERS_CRLF, |
- WINHTTP_HEADER_NAME_BY_INDEX, |
- &response_headers, |
- WINHTTP_NO_HEADER_INDEX))) { |
- return response_headers; |
- } |
- } |
- return CString(); |
-} |
- |
-uint32 SimpleRequest::ChooseProxyAuthScheme(uint32 supported_schemes) { |
- // It is the server's responsibility only to accept |
- // authentication schemes that provide a sufficient level |
- // of security to protect the server's resources. |
- // |
- // The client is also obligated only to use an authentication |
- // scheme that adequately protects its username and password. |
- // |
- // TODO(omaha): remove Basic authentication because Basic authentication |
- // exposes the client's username and password to anyone monitoring |
- // the connection. This option is here for Fiddler testing purposes. |
- |
- uint32 auth_schemes[] = { |
- WINHTTP_AUTH_SCHEME_NEGOTIATE, |
- WINHTTP_AUTH_SCHEME_NTLM, |
- WINHTTP_AUTH_SCHEME_DIGEST, |
- WINHTTP_AUTH_SCHEME_BASIC, |
- }; |
- for (int i = 0; i < arraysize(auth_schemes); ++i) { |
- if (supported_schemes & auth_schemes[i]) { |
- return auth_schemes[i]; |
- } |
- } |
- |
- return 0; |
-} |
- |
-void SimpleRequest::SetProxyInformation() { |
- bool uses_proxy = false; |
- CString proxy, proxy_bypass; |
- int access_type = NetworkConfig::GetAccessType(proxy_config_); |
- if (access_type == WINHTTP_ACCESS_TYPE_AUTO_DETECT) { |
- HttpClient::ProxyInfo proxy_info = {0}; |
- NetworkConfig* network_config = NULL; |
- NetworkConfigManager& network_manager = NetworkConfigManager::Instance(); |
- HRESULT hr = network_manager.GetUserNetworkConfig(&network_config); |
- if (SUCCEEDED(hr)) { |
- hr = network_config->GetProxyForUrl( |
- url_, |
- proxy_config_.auto_config_url, |
- &proxy_info); |
- if (SUCCEEDED(hr)) { |
- // The result of proxy auto-detection could be that either a proxy is |
- // found, or direct connection is allowed for the specified url. |
- ASSERT(proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY || |
- proxy_info.access_type == WINHTTP_ACCESS_TYPE_NO_PROXY, |
- (_T("[Unexpected access_type][%d]"), proxy_info.access_type)); |
- |
- uses_proxy = proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY; |
- |
- proxy = proxy_info.proxy; |
- proxy_bypass = proxy_info.proxy_bypass; |
- |
- ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy)); |
- ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass)); |
- } else { |
- ASSERT1(!uses_proxy); |
- NET_LOG(LW, (_T("[GetProxyForUrl failed][0x%08x]"), hr)); |
- } |
- } else { |
- NET_LOG(LW, (_T("[GetUserNetworkConfig failed][0x%08x]"), hr)); |
- } |
- } else if (access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) { |
- uses_proxy = true; |
- proxy = proxy_config_.proxy; |
- proxy_bypass = proxy_config_.proxy_bypass; |
- } |
- |
- // If a proxy is going to be used, modify the state of the object and |
- // set the proxy information on the request handle. |
- if (uses_proxy) { |
- ASSERT1(!proxy.IsEmpty()); |
- |
- request_state_->proxy = proxy; |
- request_state_->proxy_bypass = proxy_bypass; |
- |
- HttpClient::ProxyInfo proxy_info = {0}; |
- proxy_info.access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY; |
- proxy_info.proxy = request_state_->proxy; |
- proxy_info.proxy_bypass = request_state_->proxy_bypass; |
- |
- NET_LOG(L3, (_T("[using proxy %s]"), proxy_info.proxy)); |
- VERIFY1(SUCCEEDED(winhttp_adapter_->SetRequestOption(WINHTTP_OPTION_PROXY, |
- &proxy_info, |
- sizeof(proxy_info)))); |
- } |
-} |
- |
-void SimpleRequest::LogResponseHeaders() { |
- CString response_headers; |
- winhttp_adapter_->QueryRequestHeadersString(WINHTTP_QUERY_RAW_HEADERS_CRLF, |
- WINHTTP_HEADER_NAME_BY_INDEX, |
- &response_headers, |
- WINHTTP_NO_HEADER_INDEX); |
- NET_LOG(L3, (_T("[response headers...]\r\n%s"), response_headers)); |
-} |
- |
-} // namespace omaha |
- |