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