| // Copyright 2019 Google LLC |
| // |
| // 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 LLC 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. |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> // Must come first |
| #endif |
| |
| #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 |