xref: /aosp_15_r20/external/google-breakpad/src/tools/windows/converter_exe/winhttp_client.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2019 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>  // Must come first
31 #endif
32 
33 #include "tools/windows/converter_exe/winhttp_client.h"
34 
35 #include <assert.h>
36 #include <stdlib.h>
37 #include <windows.h>
38 #include <winhttp.h>
39 #include <vector>
40 
41 namespace crash {
42 
43 namespace internal {
44 
45 // This class implements HttpClient based on WinInet APIs.
46 class WinHttpClient : public HttpClient {
47  public:
~WinHttpClient()48   virtual ~WinHttpClient() {}
49   virtual bool CrackUrl(const TCHAR* url,
50                         DWORD flags,
51                         TCHAR* scheme,
52                         size_t scheme_buffer_length,
53                         TCHAR* host,
54                         size_t host_buffer_length,
55                         TCHAR* uri,
56                         size_t uri_buffer_length,
57                         int* port) const;
58   virtual bool Open(const TCHAR* user_agent,
59                     DWORD access_type,
60                     const TCHAR* proxy_name,
61                     const TCHAR* proxy_bypass,
62                     HttpHandle* session_handle) const;
63   virtual bool Connect(HttpHandle session_handle,
64                        const TCHAR* server,
65                        int port,
66                        HttpHandle* connection_handle) const;
67   virtual bool OpenRequest(HttpHandle connection_handle,
68                            const TCHAR* verb,
69                            const TCHAR* uri,
70                            const TCHAR* version,
71                            const TCHAR* referrer,
72                            bool is_secure,
73                            HttpHandle* request_handle) const;
74   virtual bool SendRequest(HttpHandle request_handle,
75                            const TCHAR* headers,
76                            DWORD headers_length) const;
77   virtual bool ReceiveResponse(HttpHandle request_handle) const;
78   virtual bool GetHttpStatusCode(HttpHandle request_handle,
79                                  int* status_code) const;
80   virtual bool GetContentLength(HttpHandle request_handle,
81                                 DWORD* content_length) const;
82   virtual bool ReadData(HttpHandle request_handle,
83                         void* buffer,
84                         DWORD buffer_length,
85                         DWORD* bytes_read) const;
86   virtual bool Close(HttpHandle handle) const;
87 
88  private:
89   static DWORD MapAccessType(DWORD access_type);
90   static HINTERNET ToHINTERNET(HttpHandle handle);
91   static HttpHandle FromHINTERNET(HINTERNET handle);
92 };
93 
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) const94 bool WinHttpClient::CrackUrl(const TCHAR* url,
95                              DWORD flags,
96                              TCHAR* scheme,
97                              size_t scheme_buffer_length,
98                              TCHAR* host,
99                              size_t host_buffer_length,
100                              TCHAR* uri,
101                              size_t uri_buffer_length,
102                              int* port) const {
103   assert(url);
104   assert(scheme);
105   assert(host);
106   assert(uri);
107   assert(port);
108 
109   URL_COMPONENTS url_comp = {0};
110   url_comp.dwStructSize = sizeof(url_comp);
111   url_comp.lpszScheme = scheme;
112   url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
113   url_comp.lpszHostName = host;
114   url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
115   url_comp.lpszUrlPath = uri;
116   url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
117 
118   bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp);
119   if (result) {
120     *port = static_cast<int>(url_comp.nPort);
121   }
122   return result;
123 }
124 
Open(const TCHAR * user_agent,DWORD access_type,const TCHAR * proxy_name,const TCHAR * proxy_bypass,HttpHandle * session_handle) const125 bool WinHttpClient::Open(const TCHAR* user_agent,
126                          DWORD access_type,
127                          const TCHAR* proxy_name,
128                          const TCHAR* proxy_bypass,
129                          HttpHandle* session_handle)  const {
130   *session_handle = FromHINTERNET(::WinHttpOpen(user_agent,
131                                                 MapAccessType(access_type),
132                                                 proxy_name,
133                                                 proxy_bypass,
134                                                 0));
135 
136   return !!(*session_handle);
137 }
138 
Connect(HttpHandle session_handle,const TCHAR * server,int port,HttpHandle * connection_handle) const139 bool WinHttpClient::Connect(HttpHandle session_handle,
140                             const TCHAR* server,
141                             int port,
142                             HttpHandle* connection_handle) const {
143   assert(server);
144 
145   // Uses NULL user name and password to connect.
146   *connection_handle = FromHINTERNET(::WinHttpConnect(
147                                          ToHINTERNET(session_handle),
148                                          server,
149                                          static_cast<INTERNET_PORT>(port),
150                                          NULL));
151   return !!(*connection_handle);
152 }
153 
OpenRequest(HttpHandle connection_handle,const TCHAR * verb,const TCHAR * uri,const TCHAR * version,const TCHAR * referrer,bool is_secure,HttpHandle * request_handle) const154 bool WinHttpClient::OpenRequest(HttpHandle connection_handle,
155                                 const TCHAR* verb,
156                                 const TCHAR* uri,
157                                 const TCHAR* version,
158                                 const TCHAR* referrer,
159                                 bool is_secure,
160                                 HttpHandle* request_handle) const {
161   assert(connection_handle);
162   assert(verb);
163   assert(uri);
164   assert(request_handle);
165 
166   *request_handle = FromHINTERNET(::WinHttpOpenRequest(
167                                       ToHINTERNET(connection_handle),
168                                       verb,
169                                       uri,
170                                       version,
171                                       referrer,
172                                       WINHTTP_DEFAULT_ACCEPT_TYPES,
173                                       is_secure ? WINHTTP_FLAG_SECURE : 0));
174   return !!(*request_handle);
175 }
176 
SendRequest(HttpHandle request_handle,const TCHAR * headers,DWORD headers_length) const177 bool WinHttpClient::SendRequest(HttpHandle request_handle,
178                                 const TCHAR* headers,
179                                 DWORD headers_length) const {
180   assert(request_handle);
181 
182   return !!::WinHttpSendRequest(ToHINTERNET(request_handle),
183                                 headers,
184                                 headers_length,
185                                 NULL,
186                                 0,
187                                 WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
188                                 NULL);
189 }
190 
ReceiveResponse(HttpHandle request_handle) const191 bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const {
192   assert(request_handle);
193 
194   return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL);
195 }
196 
GetHttpStatusCode(HttpHandle request_handle,int * status_code) const197 bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle,
198                                       int* status_code) const {
199   TCHAR http_status_string[4] = {0};
200   DWORD http_status_string_size = sizeof(http_status_string);
201   if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
202                              WINHTTP_QUERY_STATUS_CODE,
203                              WINHTTP_HEADER_NAME_BY_INDEX,
204                              static_cast<void*>(&http_status_string),
205                              &http_status_string_size, 0)) {
206     return false;
207   }
208 
209   *status_code = static_cast<DWORD>(_tcstol(http_status_string, NULL, 10));
210   return true;
211 }
212 
GetContentLength(HttpHandle request_handle,DWORD * content_length) const213 bool WinHttpClient::GetContentLength(HttpHandle request_handle,
214                                      DWORD* content_length) const {
215   assert(request_handle);
216   assert(content_length);
217 
218   TCHAR content_length_string[11] = {0};
219   DWORD content_length_string_size = sizeof(content_length_string);
220   if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
221                              WINHTTP_QUERY_CONTENT_LENGTH,
222                              WINHTTP_HEADER_NAME_BY_INDEX,
223                              static_cast<void*>(&content_length_string),
224                              &content_length_string_size, 0)) {
225     *content_length = kUnknownContentLength;
226   } else {
227     *content_length =
228         static_cast<DWORD>(wcstol(content_length_string, NULL, 10));
229   }
230   return true;
231 }
232 
ReadData(HttpHandle request_handle,void * buffer,DWORD buffer_length,DWORD * bytes_read) const233 bool WinHttpClient::ReadData(HttpHandle request_handle,
234                              void* buffer,
235                              DWORD buffer_length,
236                              DWORD* bytes_read) const {
237   assert(request_handle);
238   assert(buffer);
239   assert(bytes_read);
240 
241   DWORD bytes_read_local = 0;
242   if (!::WinHttpReadData(ToHINTERNET(request_handle),
243                          buffer,
244                          buffer_length,
245                          &bytes_read_local)) {
246     return false;
247   }
248   *bytes_read = bytes_read_local;
249   return true;
250 }
251 
Close(HttpHandle handle) const252 bool WinHttpClient::Close(HttpHandle handle) const {
253   assert(handle);
254   return !!::WinHttpCloseHandle(ToHINTERNET(handle));
255 }
256 
MapAccessType(DWORD access_type)257 DWORD WinHttpClient::MapAccessType(DWORD access_type) {
258   switch (static_cast<AccessType>(access_type)) {
259     case ACCESS_TYPE_PRECONFIG:
260     default:
261       return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
262     case ACCESS_TYPE_DIRECT:
263       return WINHTTP_ACCESS_TYPE_NO_PROXY;
264     case ACCESS_TYPE_PROXY:
265       return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
266   }
267 }
268 
269 
ToHINTERNET(HttpHandle handle)270 HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) {
271   return static_cast<HINTERNET>(handle);
272 }
273 
FromHINTERNET(HINTERNET handle)274 HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) {
275   return static_cast<HttpHandle>(handle);
276 }
277 
278 }  // namespace internal
279 
CreateWinHttpClient(const TCHAR * url)280 HttpClient* CreateWinHttpClient(const TCHAR* url) {
281   assert(url);
282 
283   internal::WinHttpClient winhttp;
284   wchar_t scheme[16] = {0};
285   wchar_t host[256] = {0};
286   wchar_t path[256] = {0};
287   int port = 0;
288 
289   if (!winhttp.CrackUrl(url,
290                         0,
291                         scheme,
292                         sizeof(scheme)/sizeof(scheme[0]),
293                         host,
294                         sizeof(host)/sizeof(host[0]),
295                         path,
296                         sizeof(path)/sizeof(path[0]),
297                         &port)) {
298     return NULL;
299   }
300 
301   if (_wcsicmp(scheme, L"https") == 0) {
302     // Winhttp under WINE doesn't support wildcard certificates, so avoid
303     // to use it if the scheme is https. The caller should fall back to
304     // use wininet if NULL is returned.
305     return NULL;
306   }
307 
308   return new internal::WinHttpClient();
309 }
310 
311 }  // namespace crash
312