xref: /aosp_15_r20/external/google-breakpad/src/tools/windows/converter_exe/wininet_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/wininet_client.h"
34 
35 #include <assert.h>
36 #include <stdlib.h>
37 #include <windows.h>
38 #include <wininet.h>
39 
40 namespace crash {
41 
42 namespace internal {
43 
44 // This class implements HttpClient based on WinInet APIs.
45 class WinInetClient : public HttpClient {
46  public:
~WinInetClient()47   virtual ~WinInetClient() {}
48   virtual bool CrackUrl(const TCHAR* url,
49                         DWORD flags,
50                         TCHAR* scheme,
51                         size_t scheme_buffer_length,
52                         TCHAR* host,
53                         size_t host_buffer_length,
54                         TCHAR* uri,
55                         size_t uri_buffer_length,
56                         int* port) const;
57   virtual bool Open(const TCHAR* user_agent,
58                     DWORD access_type,
59                     const TCHAR* proxy_name,
60                     const TCHAR* proxy_bypass,
61                     HttpHandle* session_handle) const;
62   virtual bool Connect(HttpHandle session_handle,
63                        const TCHAR* server,
64                        int port,
65                        HttpHandle* connection_handle) const;
66   virtual bool OpenRequest(HttpHandle connection_handle,
67                            const TCHAR* verb,
68                            const TCHAR* uri,
69                            const TCHAR* version,
70                            const TCHAR* referrer,
71                            bool is_secure,
72                            HttpHandle* request_handle) const;
73   virtual bool SendRequest(HttpHandle request_handle,
74                            const TCHAR* headers,
75                            DWORD headers_length) const;
76   virtual bool ReceiveResponse(HttpHandle request_handle) const;
77   virtual bool GetHttpStatusCode(HttpHandle request_handle,
78                                  int* status_code) const;
79   virtual bool GetContentLength(HttpHandle request_handle,
80                                 DWORD* content_length) const;
81   virtual bool ReadData(HttpHandle request_handle,
82                         void* buffer,
83                         DWORD buffer_length,
84                         DWORD* bytes_read) const;
85   virtual bool Close(HttpHandle handle) const;
86 
87  private:
88   static DWORD MapAccessType(DWORD access_type);
89   static HINTERNET ToHINTERNET(HttpHandle handle);
90   static HttpHandle FromHINTERNET(HINTERNET handle);
91 };
92 
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) const93 bool WinInetClient::CrackUrl(const TCHAR* url,
94                              DWORD flags,
95                              TCHAR* scheme,
96                              size_t scheme_buffer_length,
97                              TCHAR* host,
98                              size_t host_buffer_length,
99                              TCHAR* uri,
100                              size_t uri_buffer_length,
101                              int* port) const {
102   assert(url);
103   assert(scheme);
104   assert(host);
105   assert(uri);
106   assert(port);
107 
108   URL_COMPONENTS url_comp = {0};
109   url_comp.dwStructSize = sizeof(url_comp);
110   url_comp.lpszScheme = scheme;
111   url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
112   url_comp.lpszHostName = host;
113   url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
114   url_comp.lpszUrlPath = uri;
115   url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
116 
117   bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp);
118   if (result) {
119     *port = static_cast<int>(url_comp.nPort);
120   }
121   return result;
122 }
123 
Open(const TCHAR * user_agent,DWORD access_type,const TCHAR * proxy_name,const TCHAR * proxy_bypass,HttpHandle * session_handle) const124 bool WinInetClient::Open(const TCHAR* user_agent,
125                          DWORD access_type,
126                          const TCHAR* proxy_name,
127                          const TCHAR* proxy_bypass,
128                          HttpHandle* session_handle)  const {
129   *session_handle = FromHINTERNET(::InternetOpen(user_agent,
130                                                  MapAccessType(access_type),
131                                                  proxy_name,
132                                                  proxy_bypass,
133                                                  0));
134   return !!(*session_handle);
135 }
136 
Connect(HttpHandle session_handle,const TCHAR * server,int port,HttpHandle * connection_handle) const137 bool WinInetClient::Connect(HttpHandle session_handle,
138                             const TCHAR* server,
139                             int port,
140                             HttpHandle* connection_handle) const {
141   assert(server);
142 
143   // Uses NULL user name and password to connect. Always uses http service.
144   *connection_handle = FromHINTERNET(::InternetConnect(
145                                          ToHINTERNET(session_handle),
146                                          server,
147                                          static_cast<INTERNET_PORT>(port),
148                                          NULL,
149                                          NULL,
150                                          INTERNET_SERVICE_HTTP,
151                                          0,
152                                          0));
153   return !!(*connection_handle);
154 }
155 
OpenRequest(HttpHandle connection_handle,const TCHAR * verb,const TCHAR * uri,const TCHAR * version,const TCHAR * referrer,bool is_secure,HttpHandle * request_handle) const156 bool WinInetClient::OpenRequest(HttpHandle connection_handle,
157                                 const TCHAR* verb,
158                                 const TCHAR* uri,
159                                 const TCHAR* version,
160                                 const TCHAR* referrer,
161                                 bool is_secure,
162                                 HttpHandle* request_handle) const {
163   assert(connection_handle);
164   assert(verb);
165   assert(uri);
166 
167   *request_handle = FromHINTERNET(::HttpOpenRequest(
168                                       ToHINTERNET(connection_handle),
169                                       verb,
170                                       uri,
171                                       version,
172                                       referrer,
173                                       NULL,
174                                       is_secure ? INTERNET_FLAG_SECURE : 0,
175                                       NULL));
176   return !!(*request_handle);
177 }
178 
SendRequest(HttpHandle request_handle,const TCHAR * headers,DWORD headers_length) const179 bool WinInetClient::SendRequest(HttpHandle request_handle,
180                                 const TCHAR* headers,
181                                 DWORD headers_length) const {
182   assert(request_handle);
183 
184   return !!::HttpSendRequest(ToHINTERNET(request_handle),
185                              headers,
186                              headers_length,
187                              NULL,
188                              0);
189 }
190 
ReceiveResponse(HttpHandle) const191 bool WinInetClient::ReceiveResponse(HttpHandle) const {
192   return true;
193 }
194 
GetHttpStatusCode(HttpHandle request_handle,int * status_code) const195 bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle,
196                                       int* status_code) const {
197   assert(request_handle);
198 
199   TCHAR http_status_string[4] = {0};
200   DWORD http_status_string_size = sizeof(http_status_string);
201   if (!::HttpQueryInfo(ToHINTERNET(request_handle),
202                        HTTP_QUERY_STATUS_CODE,
203                        static_cast<void*>(&http_status_string),
204                        &http_status_string_size,
205                        0)) {
206     return false;
207   }
208 
209   *status_code = _tcstol(http_status_string, NULL, 10);
210   return true;
211 }
212 
GetContentLength(HttpHandle request_handle,DWORD * content_length) const213 bool WinInetClient::GetContentLength(HttpHandle request_handle,
214                                      DWORD* content_length) const {
215   assert(request_handle);
216   assert(content_length);
217 
218   TCHAR content_length_string[11];
219   DWORD content_length_string_size = sizeof(content_length_string);
220   if (!::HttpQueryInfo(ToHINTERNET(request_handle),
221                        HTTP_QUERY_CONTENT_LENGTH,
222                        static_cast<void*>(&content_length_string),
223                        &content_length_string_size,
224                        0)) {
225     *content_length = kUnknownContentLength;
226   } else {
227     *content_length = wcstol(content_length_string, NULL, 10);
228   }
229   return true;
230 }
231 
ReadData(HttpHandle request_handle,void * buffer,DWORD buffer_length,DWORD * bytes_read) const232 bool WinInetClient::ReadData(HttpHandle request_handle,
233                              void* buffer,
234                              DWORD buffer_length,
235                              DWORD* bytes_read) const {
236   assert(request_handle);
237   assert(buffer);
238   assert(bytes_read);
239 
240   DWORD bytes_read_local = 0;
241   if (!::InternetReadFile(ToHINTERNET(request_handle),
242                           buffer,
243                           buffer_length,
244                           &bytes_read_local)) {
245     return false;
246   }
247   *bytes_read = bytes_read_local;
248   return true;
249 }
250 
Close(HttpHandle handle) const251 bool WinInetClient::Close(HttpHandle handle) const {
252   assert(handle);
253   return !!::InternetCloseHandle(ToHINTERNET(handle));
254 }
255 
MapAccessType(DWORD access_type)256 DWORD WinInetClient::MapAccessType(DWORD access_type) {
257   switch (static_cast<AccessType>(access_type)) {
258     case ACCESS_TYPE_PRECONFIG:
259     default:
260       return INTERNET_OPEN_TYPE_PRECONFIG;
261     case ACCESS_TYPE_DIRECT:
262       return INTERNET_OPEN_TYPE_DIRECT;
263     case ACCESS_TYPE_PROXY:
264       return INTERNET_OPEN_TYPE_PROXY;
265   }
266 }
267 
ToHINTERNET(HttpHandle handle)268 HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) {
269   return static_cast<HINTERNET>(handle);
270 }
271 
FromHINTERNET(HINTERNET handle)272 HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) {
273   return static_cast<HttpHandle>(handle);
274 }
275 
276 }  // namespace internal
277 
CreateWinInetClient(const TCHAR *)278 HttpClient* CreateWinInetClient(const TCHAR*) {
279   return new internal::WinInetClient();
280 }
281 
282 }  // namespace crash
283