// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_WINHTTP_NETWORK_FETCHER_H_
#define COMPONENTS_WINHTTP_NETWORK_FETCHER_H_
#include <windows.h>
#include <stdint.h>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "components/winhttp/proxy_configuration.h"
#include "components/winhttp/scoped_hinternet.h"
#include "components/winhttp/scoped_winttp_proxy_info.h"
#include "url/gurl.h"
namespace base {
class SequencedTaskRunner;
}
namespace winhttp {
// Implements a network fetcher in terms of WinHTTP. The class is ref-counted
// as it is accessed from the main sequence and the worker threads in WinHTTP.
class NetworkFetcher : public base::RefCountedThreadSafe<NetworkFetcher> {
public:
using FetchCompleteCallback = base::OnceCallback<void(int response_code)>;
using FetchStartedCallback =
base::OnceCallback<void(int response_code, int64_t content_length)>;
using FetchProgressCallback = base::RepeatingCallback<void(int64_t current)>;
NetworkFetcher(scoped_refptr<SharedHInternet> session_handle,
scoped_refptr<ProxyConfiguration> proxy_configuration);
NetworkFetcher(const NetworkFetcher&) = delete;
NetworkFetcher& operator=(const NetworkFetcher&) = delete;
void Close();
void PostRequest(
const GURL& url,
const std::string& post_data,
const std::string& content_type,
const base::flat_map<std::string, std::string>& post_additional_headers,
FetchStartedCallback fetch_started_callback,
FetchProgressCallback fetch_progress_callback,
FetchCompleteCallback fetch_complete_callback);
// Downloads the content of the |url| to a file identified by |file_path|.
// The content is written to the file as it is being retrieved from the
// network. Returns a closure that can be run to cancel the download.
base::OnceClosure DownloadToFile(
const GURL& url,
const base::FilePath& file_path,
FetchStartedCallback fetch_started_callback,
FetchProgressCallback fetch_progress_callback,
FetchCompleteCallback fetch_complete_callback);
HRESULT QueryHeaderString(const std::wstring& name,
std::wstring* value) const;
HRESULT QueryHeaderInt(const std::wstring& name, int* value) const;
std::string GetResponseBody() const;
HRESULT GetNetError() const;
base::FilePath GetFilePath() const;
// Returns the number of bytes retrieved from the network. This may be
// different than the content length if an error occurred.
int64_t GetContentSize() const;
private:
friend class base::RefCountedThreadSafe<NetworkFetcher>;
using WriteDataCallback = base::RepeatingCallback<void()>;
~NetworkFetcher();
static void __stdcall WinHttpStatusCallback(HINTERNET handle,
DWORD_PTR context,
DWORD status,
void* info,
DWORD info_len);
// Invoked by the last WinHTTPstatus status callback.
void HandleClosing();
DWORD_PTR context() const { return reinterpret_cast<DWORD_PTR>(this); }
HRESULT BeginFetch(
const std::string& data,
const base::flat_map<std::string, std::string>& additional_headers);
std::optional<ScopedWinHttpProxyInfo> GetProxyForUrl();
void ContinueFetch(
const std::string& data,
base::flat_map<std::string, std::string> additional_headers,
std::optional<ScopedWinHttpProxyInfo> winhttp_proxy_info);
ScopedHInternet Connect();
ScopedHInternet OpenRequest();
HRESULT SendRequest(const std::string& data);
void SendRequestComplete();
HRESULT ReceiveResponse();
void HeadersAvailable();
HRESULT ReadData();
void ReadDataComplete(size_t num_bytes_read);
void RequestError(DWORD error);
void CompleteFetch();
void WriteDataToMemory();
void WriteDataToFile();
bool WriteDataToFileBlocking();
void WriteDataToFileComplete(bool is_eof);
SEQUENCE_CHECKER(sequence_checker_);
scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
scoped_refptr<SharedHInternet> session_handle_;
scoped_refptr<ProxyConfiguration> proxy_configuration_;
ScopedHInternet connect_handle_;
ScopedHInternet request_handle_;
// Keeps an outstanding reference count on itself as long as there is a
// valid request handle and the context for the handle is set to this
// instance.
scoped_refptr<NetworkFetcher> self_;
GURL url_;
bool is_https_ = false;
std::string host_;
int port_ = 0;
std::string path_for_request_;
std::wstring_view verb_;
std::string request_data_;
// The value of Content-Type header, e.g. "application/json".
std::string content_type_;
WriteDataCallback write_data_callback_;
HRESULT net_error_ = S_OK;
std::vector<char> read_buffer_;
int response_code_ = 0;
std::string post_response_body_;
base::FilePath file_path_;
base::File file_;
int64_t content_size_ = 0;
FetchStartedCallback fetch_started_callback_;
FetchProgressCallback fetch_progress_callback_;
FetchCompleteCallback fetch_complete_callback_;
};
} // namespace winhttp
#endif // COMPONENTS_WINHTTP_NETWORK_FETCHER_H_