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