Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/cpp/iedriverserver/IEDriverServer.cpp
2867 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
17
#include "stdafx.h"
18
#include "resource.h"
19
#include "CommandLineArguments.h"
20
#include "IEServer.h"
21
#include <algorithm>
22
#include <iostream>
23
#include <map>
24
#include <iostream>
25
#include <string>
26
#include <vector>
27
28
// The prototypes for these functions must match those exported
29
// by the .dll produced by the IEDriver project in this solution.
30
// The definitions of these functions can be found in WebDriver.h
31
// in that project.
32
typedef void* (__cdecl *STARTSERVERPROC)(int, const std::wstring&, const std::wstring&, const std::wstring&, const std::wstring&, const std::wstring&);
33
typedef void (__cdecl *STOPSERVERPROC)(void);
34
35
#define ERR_DLL_EXTRACT_FAIL 1
36
#define ERR_DLL_LOAD_FAIL 2
37
#define ERR_FUNCTION_NOT_FOUND 3
38
#define ERR_SERVER_START 4
39
40
#define RESOURCE_TYPE L"BINARY"
41
#define TEMP_FILE_PREFIX L"IEDriver"
42
#define START_SERVER_EX_API_NAME "StartServer"
43
#define STOP_SERVER_API_NAME "StopServer"
44
45
#define PORT_COMMAND_LINE_ARG L"port"
46
#define HOST_COMMAND_LINE_ARG L"host"
47
#define LOGLEVEL_COMMAND_LINE_ARG L"log-level"
48
#define LOGFILE_COMMAND_LINE_ARG L"log-file"
49
#define SILENT_COMMAND_LINE_ARG L"silent"
50
#define EXTRACTPATH_COMMAND_LINE_ARG L"extract-path"
51
#define ACL_COMMAND_LINE_ARG L"whitelisted-ips"
52
#define BOOLEAN_COMMAND_LINE_ARG_MISSING_VALUE L"value-not-specified"
53
54
bool ExtractResource(unsigned short resource_id,
55
const std::wstring& output_file_name) {
56
bool success = false;
57
try {
58
// First find and load the required resource
59
HRSRC resource_handle = ::FindResource(NULL,
60
MAKEINTRESOURCE(resource_id),
61
RESOURCE_TYPE);
62
HGLOBAL global_resouce_handle = ::LoadResource(NULL, resource_handle);
63
64
// Now open and map this to a disk file
65
LPVOID file_pointer = ::LockResource(global_resouce_handle);
66
DWORD resource_size = ::SizeofResource(NULL, resource_handle);
67
68
// Open the file and filemap
69
HANDLE file_handle = ::CreateFile(output_file_name.c_str(),
70
GENERIC_READ | GENERIC_WRITE,
71
0,
72
NULL,
73
CREATE_ALWAYS,
74
FILE_ATTRIBUTE_NORMAL,
75
NULL);
76
HANDLE file_mapping_handle = ::CreateFileMapping(file_handle,
77
NULL,
78
PAGE_READWRITE,
79
0,
80
resource_size,
81
NULL);
82
LPVOID base_address_pointer = ::MapViewOfFile(file_mapping_handle,
83
FILE_MAP_WRITE,
84
0,
85
0,
86
0);
87
88
// Write the file
89
::CopyMemory(base_address_pointer, file_pointer, resource_size);
90
91
// Unmap the file and close the handles
92
::UnmapViewOfFile(base_address_pointer);
93
::CloseHandle(file_mapping_handle);
94
::CloseHandle(file_handle);
95
success = true;
96
} catch(...) {
97
// Ignore all type of errors
98
}
99
return success;
100
}
101
102
std::wstring GetProcessArchitectureDescription() {
103
std::wstring arch_description = L"32-bit";
104
SYSTEM_INFO system_info;
105
::GetNativeSystemInfo(&system_info);
106
if (system_info.wProcessorArchitecture != 0) {
107
BOOL is_emulated;
108
HANDLE process_handle = ::GetCurrentProcess();
109
::IsWow64Process(process_handle, &is_emulated);
110
if (!is_emulated) {
111
arch_description = L"64-bit";
112
}
113
::CloseHandle(process_handle);
114
}
115
116
return arch_description;
117
}
118
119
std::wstring GetExecutableVersion() {
120
struct LANGANDCODEPAGE {
121
WORD language;
122
WORD code_page;
123
} *lang_info;
124
125
// get the filename of the executable containing the version resource
126
std::vector<wchar_t> file_name_buffer(MAX_PATH + 1);
127
::GetModuleFileNameW(NULL, &file_name_buffer[0], MAX_PATH);
128
129
DWORD dummy;
130
DWORD length = ::GetFileVersionInfoSizeW(&file_name_buffer[0],
131
&dummy);
132
std::vector<BYTE> version_buffer(length);
133
::GetFileVersionInfoW(&file_name_buffer[0],
134
dummy,
135
length,
136
&version_buffer[0]);
137
138
UINT page_count;
139
BOOL query_result = ::VerQueryValueW(&version_buffer[0],
140
L"\\VarFileInfo\\Translation",
141
reinterpret_cast<void**>(&lang_info),
142
&page_count);
143
144
wchar_t sub_block[MAX_PATH];
145
_snwprintf_s(sub_block,
146
MAX_PATH,
147
MAX_PATH,
148
L"\\StringFileInfo\\%04x%04x\\FileVersion",
149
lang_info->language,
150
lang_info->code_page);
151
LPVOID value = NULL;
152
UINT size;
153
query_result = ::VerQueryValueW(&version_buffer[0],
154
sub_block,
155
&value,
156
&size);
157
return static_cast<wchar_t*>(value);
158
}
159
160
161
void ShowUsage(void) {
162
std::wcout << L"Launches the WebDriver server for the Internet Explorer driver" << std::endl
163
<< std::endl
164
<< L"IEDriverServer [/port=<port>] [/host=<host>] [/log-level=<level>]" << std::endl
165
<< L" [/log-file=<file>] [/extract-path=<path>] [/silent]" << std::endl
166
<< L" [/whitelisted-ips=<whitelisted-ips>] [/version]" << std::endl
167
<< std::endl
168
<< L" /port=<port> Specifies the port on which the server will listen for" << std::endl
169
<< L" commands. Defaults to 5555 if not specified." << std::endl
170
<< L" /host=<host> Specifies the address of the host adapter on which the server" << std::endl
171
<< L" will listen for commands." << std::endl
172
<< L" /log-level=<level>" << std::endl
173
<< L" Specifies the log level used by the server. Valid values are:" << std::endl
174
<< L" TRACE, DEBUG, INFO, WARN, ERROR, and FATAL. Defaults to FATAL" << std::endl
175
<< L" if not specified." << std::endl
176
<< L" /log-file=<file>" << std::endl
177
<< L" Specifies the full path and file name of the log file used by" << std::endl
178
<< L" the server. Defaults logging to stdout if not specified. " << std::endl
179
<< L" /extract-path=<path>" << std::endl
180
<< L" Specifies the full path to the directory used to extract" << std::endl
181
<< L" supporting files used by the server. Defaults to the TEMP" << std::endl
182
<< L" directory if not specified." << std::endl
183
<< L" /silent Suppresses diagnostic output when the server is started." << std::endl
184
<< L" /whitelisted-ips=<whitelisted-ips>" << std::endl
185
<< L" Comma-separated whitelist of remote IPv4 addresses which" << std::endl
186
<< L" are allowed to connect to the WebDriver server." << std::endl
187
<< L" /version Displays version information and exits. All other arguments" << std::endl
188
<< L" are ignored." << std::endl;
189
}
190
191
int _tmain(int argc, _TCHAR* argv[]) {
192
CommandLineArguments args(argc, argv);
193
if (args.is_help_requested()) {
194
ShowUsage();
195
return 0;
196
}
197
vector<TCHAR> temp_file_name_buffer(MAX_PATH);
198
vector<TCHAR> temp_path_buffer(MAX_PATH);
199
200
// Gets the temp path env string (no guarantee it's a valid path).
201
unsigned long temp_path_length = ::GetTempPath(MAX_PATH,
202
&temp_path_buffer[0]);
203
204
std::wstring extraction_path(&temp_path_buffer[0]);
205
206
std::wstring extraction_path_arg = args.GetValue(EXTRACTPATH_COMMAND_LINE_ARG, L"");
207
if (extraction_path_arg.size() != 0) {
208
extraction_path = extraction_path_arg;
209
}
210
211
if (extraction_path.size() > 0 &&
212
extraction_path[extraction_path.size() - 1] != L'\\') {
213
extraction_path.append(L"\\");
214
}
215
216
std::wstring initial_file = extraction_path + TEMP_FILE_PREFIX + L".tmp";
217
std::wstring temp_file_name = initial_file;
218
WIN32_FIND_DATA find_file_data;
219
HANDLE file_handle = ::FindFirstFile(initial_file.c_str(), &find_file_data);
220
if (file_handle != INVALID_HANDLE_VALUE) {
221
::FindClose(file_handle);
222
unsigned int error_code = ::GetTempFileName(extraction_path.c_str(),
223
TEMP_FILE_PREFIX,
224
0,
225
&temp_file_name_buffer[0]);
226
227
temp_file_name = &temp_file_name_buffer[0];
228
}
229
230
if (!ExtractResource(IDR_DRIVER_LIBRARY, temp_file_name)) {
231
std::wcout << L"Failed to extract the library to temp directory: "
232
<< temp_file_name;
233
return ERR_DLL_EXTRACT_FAIL;
234
}
235
236
HMODULE module_handle = ::LoadLibrary(temp_file_name.c_str());
237
if (module_handle == NULL) {
238
std::wcout << L"Failed to load the library from temp directory: "
239
<< temp_file_name;
240
return ERR_DLL_LOAD_FAIL;
241
}
242
243
STARTSERVERPROC start_server_ex_proc = reinterpret_cast<STARTSERVERPROC>(
244
::GetProcAddress(module_handle, START_SERVER_EX_API_NAME));
245
STOPSERVERPROC stop_server_proc = reinterpret_cast<STOPSERVERPROC>(
246
::GetProcAddress(module_handle, STOP_SERVER_API_NAME));
247
if (start_server_ex_proc == NULL || stop_server_proc == NULL) {
248
std::wcout << L"Could not find entry point in extracted library: "
249
<< temp_file_name;
250
return ERR_FUNCTION_NOT_FOUND;
251
}
252
253
int port = _wtoi(args.GetValue(PORT_COMMAND_LINE_ARG, L"5555").c_str());
254
std::wstring host_address = args.GetValue(HOST_COMMAND_LINE_ARG, L"");
255
std::wstring log_level = args.GetValue(LOGLEVEL_COMMAND_LINE_ARG, L"");
256
std::wstring log_file = args.GetValue(LOGFILE_COMMAND_LINE_ARG, L"");
257
bool silent = args.GetValue(SILENT_COMMAND_LINE_ARG,
258
BOOLEAN_COMMAND_LINE_ARG_MISSING_VALUE).size() == 0;
259
std::wstring executable_version = GetExecutableVersion();
260
std::wstring executable_architecture = GetProcessArchitectureDescription();
261
std::wstring implementation = L"";
262
std::wstring whitelist = args.GetValue(ACL_COMMAND_LINE_ARG, L"");
263
264
// coerce log level and implementation to uppercase, making the values
265
// case-insensitive, to match expected values.
266
std::transform(log_level.begin(),
267
log_level.end(),
268
log_level.begin(),
269
toupper);
270
std::transform(implementation.begin(),
271
implementation.end(),
272
implementation.begin(),
273
toupper);
274
275
if (args.is_version_requested()) {
276
std::wcout << L"IEDriverServer.exe"
277
<< L" " << executable_version
278
<< L" (" << executable_architecture << L")" << std::endl;
279
} else {
280
void* server_value = start_server_ex_proc(port,
281
host_address,
282
log_level,
283
log_file,
284
executable_version + L" (" + executable_architecture + L")",
285
whitelist);
286
if (server_value == NULL) {
287
std::wcout << L"Failed to start the server with: "
288
<< L"port = '" << port << L"', "
289
<< L"host = '" << host_address << L"', "
290
<< L"log level = '" << log_level << L"', "
291
<< L"log file = '" << log_file << L"', "
292
<< L"whitelisted ips = '" << whitelist << L"'.";
293
return ERR_SERVER_START;
294
}
295
if (!silent) {
296
std::wcout << L"Started InternetExplorerDriver server"
297
<< L" (" << executable_architecture << L")"
298
<< std::endl;
299
std::wcout << executable_version
300
<< std::endl;
301
std::wcout << L"Listening on port " << port << std::endl;
302
if (host_address.size() > 0) {
303
std::wcout << L"Bound to network adapter with IP address "
304
<< host_address
305
<< std::endl;
306
}
307
if (log_level.size() > 0) {
308
std::wcout << L"Log level is set to "
309
<< log_level
310
<< std::endl;
311
}
312
if (log_file.size() > 0) {
313
std::wcout << L"Log file is set to "
314
<< log_file
315
<< std::endl;
316
}
317
if (extraction_path_arg.size() > 0) {
318
std::wcout << L"Library extracted to "
319
<< extraction_path_arg
320
<< std::endl;
321
}
322
if (whitelist.size() > 0) {
323
std::wcout << L"IP addresses allowed to connect are "
324
<< whitelist
325
<< std::endl;
326
} else {
327
std::wcout << L"Only local connections are allowed"
328
<< std::endl;
329
}
330
}
331
332
// Create the shutdown event and wait for it to be signaled.
333
DWORD process_id = ::GetCurrentProcessId();
334
vector<wchar_t> process_id_buffer(10);
335
_ltow_s(process_id, &process_id_buffer[0], process_id_buffer.size(), 10);
336
std::wstring process_id_string(&process_id_buffer[0]);
337
std::wstring event_name = IESERVER_SHUTDOWN_EVENT_NAME + process_id_string;
338
HANDLE event_handle = ::CreateEvent(NULL,
339
TRUE,
340
FALSE,
341
event_name.c_str());
342
::WaitForSingleObject(event_handle, INFINITE);
343
::CloseHandle(event_handle);
344
stop_server_proc();
345
}
346
347
::FreeLibrary(module_handle);
348
::DeleteFile(temp_file_name.c_str());
349
return 0;
350
}
351
352