28 const std::wstring
uri;
30 const std::string
data;
80 DWORD error_code = GetLastError();
82 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, GetModuleHandle(L
"winhttp.dll"), error_code,
83 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer,
static_cast<DWORD
>(std::size(buffer)),
nullptr) == 0) {
84 return fmt::format(
"unknown error {}", error_code);
107 case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME:
108 case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED:
109 case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER:
110 case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER:
111 case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
112 case WINHTTP_CALLBACK_STATUS_REQUEST_SENT:
113 case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:
114 case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:
115 case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION:
116 case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:
117 case WINHTTP_CALLBACK_STATUS_HANDLE_CREATED:
118 case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
122 case WINHTTP_CALLBACK_STATUS_REDIRECT:
124 if (this->
depth++ > 5) {
125 Debug(net, 0,
"HTTP request failed: too many redirects");
132 case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
134 WinHttpReceiveResponse(this->
request,
nullptr);
137 case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
140 DWORD status_code = 0;
141 DWORD status_code_size =
sizeof(status_code);
142 WinHttpQueryHeaders(this->
request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &status_code_size, WINHTTP_NO_HEADER_INDEX);
143 Debug(net, 3,
"HTTP request status code: {}", status_code);
146 if (status_code >= 400) {
155 WinHttpQueryDataAvailable(this->
request,
nullptr);
158 case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
161 DWORD size = *(DWORD *)info;
165 char *buffer = size == 0 ? nullptr :
new char[size];
166 WinHttpReadData(this->
request, buffer, size, 0);
169 case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
170 Debug(net, 6,
"HTTP callback: {} bytes", length);
172 this->
callback.OnReceiveData(std::unique_ptr<
char[]>(
static_cast<char *
>(info)), length);
177 Debug(net, 1,
"HTTP request succeeded");
180 WinHttpQueryDataAvailable(this->
request,
nullptr);
185 case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
186 case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
193 Debug(net, 0,
"HTTP request failed: unexpected callback code 0x{:x}", code);
209 if (context == 0)
return;
224 Debug(net, 1,
"HTTP request to {}", std::string(
uri.begin(),
uri.end()));
226 URL_COMPONENTS url_components = {};
228 wchar_t hostname[128];
229 wchar_t url_path[4096];
232 url_components.dwStructSize =
sizeof(url_components);
233 url_components.lpszScheme = scheme;
234 url_components.dwSchemeLength =
static_cast<DWORD
>(std::size(scheme));
235 url_components.lpszHostName = hostname;
236 url_components.dwHostNameLength =
static_cast<DWORD
>(std::size(hostname));
237 url_components.lpszUrlPath = url_path;
238 url_components.dwUrlPathLength =
static_cast<DWORD
>(std::size(url_path));
239 WinHttpCrackUrl(this->
uri.c_str(), 0, 0, &url_components);
250 this->
request = WinHttpOpenRequest(
connection,
data.empty() ? L
"GET" : L
"POST", url_components.lpszUrlPath,
nullptr, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, url_components.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0);
251 if (this->
request ==
nullptr) {
262 WinHttpSendRequest(this->
request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0,
reinterpret_cast<DWORD_PTR
>(
this));
265 LPCWSTR content_type =
data.starts_with(
"{") ? L
"Content-Type: application/json\r\n" : L
"Content-Type: application/x-www-form-urlencoded\r\n";
266 WinHttpSendRequest(this->
request, content_type, -1,
const_cast<char *
>(
data.data()),
static_cast<DWORD
>(
data.size()),
static_cast<DWORD
>(
data.size()),
reinterpret_cast<DWORD_PTR
>(
this));
277 if (this->
callback.cancelled && !this->finished) {
278 Debug(net, 1,
"HTTP request failed: cancelled by user");
295 WinHttpCloseHandle(this->
request);
305 auto request =
new NetworkHTTPRequest(std::wstring(uri.begin(), uri.end()), callback, std::move(data));
328 callback->HandleQueue();
345 NetworkHTTPRequest *cur = *it;
361 _winhttp_session = WinHttpOpen(std::wstring(user_agent.begin(), user_agent.end()).c_str(), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC);
Converts a HTTPCallback to a Thread-Safe variant.
bool Receive()
Poll and process the HTTP request/response.
std::atomic< bool > finished
Whether we are finished with the request.
HINTERNET connection
Current connection object.
const std::string data
Data to send, if any.
~NetworkHTTPRequest()
Remove ourselves from the callback list.
NetworkHTTPRequest(std::string_view uri, HTTPCallback *callback, std::string &&data)
Create a new HTTP request.
HINTERNET request
Current request object.
void Connect()
Start the HTTP request handling.
HTTPThreadSafeCallback callback
Callback to send data back on.
void WinHttpCallback(DWORD code, void *info, DWORD length)
Callback from the WinHTTP library, called when-ever something changes about the HTTP request status.
const std::string uri
URI to connect to.
int depth
Current redirect depth we are in.
static void Connect(std::string_view uri, HTTPCallback *callback, std::string &&data="")
Connect to the given URI.
static void HTTPReceive()
Do the receiving for all HTTP connections.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Basic functions to send and receive HTTP packets.
constexpr int HTTP_429_TOO_MANY_REQUESTS
HTTP error code for when the client is doing too many requests.
static std::queue< std::unique_ptr< NetworkHTTPRequest > > _http_requests
HTTP requests that are currently running.
static std::vector< HTTPThreadSafeCallback * > _new_http_callbacks
Callbacks for the request that should be started.
static std::mutex _http_callback_mutex
Mutex to prevent concurrent access to _http_callbacks.
static std::mutex _new_http_callback_mutex
Mutex to prevent concurrent access to _new_http_callbacks.
static std::vector< HTTPThreadSafeCallback * > _http_callbacks
Callback for the current requests.
Shared functions for implementations of HTTP requests.
static HINTERNET _winhttp_session
Currently running download session.
static std::string GetLastErrorAsString()
Gets the last error from Windows as a string.
static void StaticWinHttpCallback(HINTERNET, DWORD_PTR context, DWORD code, void *info, DWORD length)
Implementation of Microsoft's WINHTTP_STATUS_CALLBACK.
void NetworkHTTPInitialize()
Initialize the HTTP socket handler.
static std::mutex _new_http_requests_mutex
Mutex to prevent concurrent access _new_http_requests.
static std::vector< HTTPThreadSafeCallback * > _new_http_callbacks
Callbacks for the request that should be started.
static std::vector< NetworkHTTPRequest * > _new_http_requests
HTTP requests that should be started.
static std::mutex _http_callback_mutex
Mutex to prevent concurrent access to _http_callbacks.
static std::mutex _new_http_callback_mutex
Mutex to prevent concurrent access to _new_http_callbacks.
void NetworkHTTPUninitialize()
Uninitialize the HTTP socket handler.
static std::vector< HTTPThreadSafeCallback * > _http_callbacks
Callback for the current requests.
std::string_view GetNetworkRevisionString()
Get the network version string used by this build.
Variables and function used internally.
Declaration of OTTD revision dependent variables.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
Callback for when the HTTP handler has something to tell us.
std::string FS2OTTD(std::wstring_view name)
Convert to OpenTTD's encoding from a wide string.
std::mutex lock
synchronization for playback status fields