// Copyright 2019 Google Inc. All rights reserved. | |
// | |
// Redistribution and use in source and binary forms, with or without | |
// modification, are permitted provided that the following conditions are | |
// met: | |
// | |
// * Redistributions of source code must retain the above copyright | |
// notice, this list of conditions and the following disclaimer. | |
// * Redistributions in binary form must reproduce the above | |
// copyright notice, this list of conditions and the following disclaimer | |
// in the documentation and/or other materials provided with the | |
// distribution. | |
// * Neither the name of Google Inc. nor the names of its | |
// contributors may be used to endorse or promote products derived from | |
// this software without specific prior written permission. | |
// | |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
#include "tools/windows/converter_exe/wininet_client.h" | |
#include <assert.h> | |
#include <stdlib.h> | |
#include <windows.h> | |
#include <wininet.h> | |
namespace crash { | |
namespace internal { | |
// This class implements HttpClient based on WinInet APIs. | |
class WinInetClient : public HttpClient { | |
public: | |
virtual ~WinInetClient() {} | |
virtual bool CrackUrl(const TCHAR* url, | |
DWORD flags, | |
TCHAR* scheme, | |
size_t scheme_buffer_length, | |
TCHAR* host, | |
size_t host_buffer_length, | |
TCHAR* uri, | |
size_t uri_buffer_length, | |
int* port) const; | |
virtual bool Open(const TCHAR* user_agent, | |
DWORD access_type, | |
const TCHAR* proxy_name, | |
const TCHAR* proxy_bypass, | |
HttpHandle* session_handle) const; | |
virtual bool Connect(HttpHandle session_handle, | |
const TCHAR* server, | |
int port, | |
HttpHandle* connection_handle) const; | |
virtual bool OpenRequest(HttpHandle connection_handle, | |
const TCHAR* verb, | |
const TCHAR* uri, | |
const TCHAR* version, | |
const TCHAR* referrer, | |
bool is_secure, | |
HttpHandle* request_handle) const; | |
virtual bool SendRequest(HttpHandle request_handle, | |
const TCHAR* headers, | |
DWORD headers_length) const; | |
virtual bool ReceiveResponse(HttpHandle request_handle) const; | |
virtual bool GetHttpStatusCode(HttpHandle request_handle, | |
int* status_code) const; | |
virtual bool GetContentLength(HttpHandle request_handle, | |
DWORD* content_length) const; | |
virtual bool ReadData(HttpHandle request_handle, | |
void* buffer, | |
DWORD buffer_length, | |
DWORD* bytes_read) const; | |
virtual bool Close(HttpHandle handle) const; | |
private: | |
static DWORD MapAccessType(DWORD access_type); | |
static HINTERNET ToHINTERNET(HttpHandle handle); | |
static HttpHandle FromHINTERNET(HINTERNET handle); | |
}; | |
bool WinInetClient::CrackUrl(const TCHAR* url, | |
DWORD flags, | |
TCHAR* scheme, | |
size_t scheme_buffer_length, | |
TCHAR* host, | |
size_t host_buffer_length, | |
TCHAR* uri, | |
size_t uri_buffer_length, | |
int* port) const { | |
assert(url); | |
assert(scheme); | |
assert(host); | |
assert(uri); | |
assert(port); | |
URL_COMPONENTS url_comp = {0}; | |
url_comp.dwStructSize = sizeof(url_comp); | |
url_comp.lpszScheme = scheme; | |
url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length); | |
url_comp.lpszHostName = host; | |
url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length); | |
url_comp.lpszUrlPath = uri; | |
url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length); | |
bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp); | |
if (result) { | |
*port = static_cast<int>(url_comp.nPort); | |
} | |
return result; | |
} | |
bool WinInetClient::Open(const TCHAR* user_agent, | |
DWORD access_type, | |
const TCHAR* proxy_name, | |
const TCHAR* proxy_bypass, | |
HttpHandle* session_handle) const { | |
*session_handle = FromHINTERNET(::InternetOpen(user_agent, | |
MapAccessType(access_type), | |
proxy_name, | |
proxy_bypass, | |
0)); | |
return !!(*session_handle); | |
} | |
bool WinInetClient::Connect(HttpHandle session_handle, | |
const TCHAR* server, | |
int port, | |
HttpHandle* connection_handle) const { | |
assert(server); | |
// Uses NULL user name and password to connect. Always uses http service. | |
*connection_handle = FromHINTERNET(::InternetConnect( | |
ToHINTERNET(session_handle), | |
server, | |
static_cast<INTERNET_PORT>(port), | |
NULL, | |
NULL, | |
INTERNET_SERVICE_HTTP, | |
0, | |
0)); | |
return !!(*connection_handle); | |
} | |
bool WinInetClient::OpenRequest(HttpHandle connection_handle, | |
const TCHAR* verb, | |
const TCHAR* uri, | |
const TCHAR* version, | |
const TCHAR* referrer, | |
bool is_secure, | |
HttpHandle* request_handle) const { | |
assert(connection_handle); | |
assert(verb); | |
assert(uri); | |
*request_handle = FromHINTERNET(::HttpOpenRequest( | |
ToHINTERNET(connection_handle), | |
verb, | |
uri, | |
version, | |
referrer, | |
NULL, | |
is_secure ? INTERNET_FLAG_SECURE : 0, | |
NULL)); | |
return !!(*request_handle); | |
} | |
bool WinInetClient::SendRequest(HttpHandle request_handle, | |
const TCHAR* headers, | |
DWORD headers_length) const { | |
assert(request_handle); | |
return !!::HttpSendRequest(ToHINTERNET(request_handle), | |
headers, | |
headers_length, | |
NULL, | |
0); | |
} | |
bool WinInetClient::ReceiveResponse(HttpHandle) const { | |
return true; | |
} | |
bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle, | |
int* status_code) const { | |
assert(request_handle); | |
TCHAR http_status_string[4] = {0}; | |
DWORD http_status_string_size = sizeof(http_status_string); | |
if (!::HttpQueryInfo(ToHINTERNET(request_handle), | |
HTTP_QUERY_STATUS_CODE, | |
static_cast<void *>(&http_status_string), | |
&http_status_string_size, | |
0)) { | |
return false; | |
} | |
*status_code = _tcstol(http_status_string, NULL, 10); | |
return true; | |
} | |
bool WinInetClient::GetContentLength(HttpHandle request_handle, | |
DWORD* content_length) const { | |
assert(request_handle); | |
assert(content_length); | |
TCHAR content_length_string[11]; | |
DWORD content_length_string_size = sizeof(content_length_string); | |
if (!::HttpQueryInfo(ToHINTERNET(request_handle), | |
HTTP_QUERY_CONTENT_LENGTH, | |
static_cast<void *>(&content_length_string), | |
&content_length_string_size, | |
0)) { | |
*content_length = kUnknownContentLength; | |
} else { | |
*content_length = wcstol(content_length_string, NULL, 10); | |
} | |
return true; | |
} | |
bool WinInetClient::ReadData(HttpHandle request_handle, | |
void* buffer, | |
DWORD buffer_length, | |
DWORD* bytes_read) const { | |
assert(request_handle); | |
assert(buffer); | |
assert(bytes_read); | |
DWORD bytes_read_local = 0; | |
if (!::InternetReadFile(ToHINTERNET(request_handle), | |
buffer, | |
buffer_length, | |
&bytes_read_local)) { | |
return false; | |
} | |
*bytes_read = bytes_read_local; | |
return true; | |
} | |
bool WinInetClient::Close(HttpHandle handle) const { | |
assert(handle); | |
return !!::InternetCloseHandle(ToHINTERNET(handle)); | |
} | |
DWORD WinInetClient::MapAccessType(DWORD access_type) { | |
switch (static_cast<AccessType>(access_type)) { | |
case ACCESS_TYPE_PRECONFIG: | |
default: | |
return INTERNET_OPEN_TYPE_PRECONFIG; | |
case ACCESS_TYPE_DIRECT: | |
return INTERNET_OPEN_TYPE_DIRECT; | |
case ACCESS_TYPE_PROXY: | |
return INTERNET_OPEN_TYPE_PROXY; | |
} | |
} | |
HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) { | |
return static_cast<HINTERNET>(handle); | |
} | |
HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) { | |
return static_cast<HttpHandle>(handle); | |
} | |
} // namespace internal | |
HttpClient* CreateWinInetClient(const TCHAR*) { | |
return new internal::WinInetClient(); | |
} | |
} // namespace crash |