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