OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/test/test_server.h" | 5 #include "net/test/test_server.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <wincrypt.h> | 8 #include <wincrypt.h> |
9 | 9 |
10 #include "base/base_paths.h" | 10 #include "base/base_paths.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/file_util.h" | 12 #include "base/file_util.h" |
13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
14 #include "base/path_service.h" | 14 #include "base/path_service.h" |
15 #include "base/string_number_conversions.h" | 15 #include "base/string_number_conversions.h" |
16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
17 #include "base/test/test_timeouts.h" | 17 #include "base/test/test_timeouts.h" |
18 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
19 #include "base/utf_string_conversions.h" | 19 #include "base/utf_string_conversions.h" |
20 #include "base/win/scoped_handle.h" | 20 #include "base/win/scoped_handle.h" |
21 | 21 |
22 #pragma comment(lib, "crypt32.lib") | 22 #pragma comment(lib, "crypt32.lib") |
23 | 23 |
24 namespace { | 24 namespace { |
25 | 25 |
26 bool LaunchTestServerAsJob(const CommandLine& cmdline, | |
27 bool start_hidden, | |
28 base::ProcessHandle* process_handle, | |
29 base::win::ScopedHandle* job_handle) { | |
30 // Launch test server process. | |
31 STARTUPINFO startup_info = {0}; | |
32 startup_info.cb = sizeof(startup_info); | |
33 startup_info.dwFlags = STARTF_USESHOWWINDOW; | |
34 startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW; | |
35 PROCESS_INFORMATION process_info; | |
36 | |
37 // If this code is run under a debugger, the test server process is | |
38 // automatically associated with a job object created by the debugger. | |
39 // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. | |
40 if (!CreateProcess( | |
41 NULL, const_cast<wchar_t*>(cmdline.GetCommandLineString().c_str()), | |
42 NULL, NULL, TRUE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, | |
43 &startup_info, &process_info)) { | |
44 LOG(ERROR) << "Could not create process."; | |
45 return false; | |
46 } | |
47 CloseHandle(process_info.hThread); | |
48 | |
49 // If the caller wants the process handle, we won't close it. | |
50 if (process_handle) { | |
51 *process_handle = process_info.hProcess; | |
52 } else { | |
53 CloseHandle(process_info.hProcess); | |
54 } | |
55 | |
56 // Create a JobObject and associate the test server process with it. | |
57 job_handle->Set(CreateJobObject(NULL, NULL)); | |
58 if (!job_handle->IsValid()) { | |
59 LOG(ERROR) << "Could not create JobObject."; | |
60 return false; | |
61 } else { | |
62 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; | |
63 limit_info.BasicLimitInformation.LimitFlags = | |
64 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; | |
65 if (0 == SetInformationJobObject(job_handle->Get(), | |
66 JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info))) { | |
67 LOG(ERROR) << "Could not SetInformationJobObject."; | |
68 return false; | |
69 } | |
70 if (0 == AssignProcessToJobObject(job_handle->Get(), | |
71 process_info.hProcess)) { | |
72 LOG(ERROR) << "Could not AssignProcessToObject."; | |
73 return false; | |
74 } | |
75 } | |
76 return true; | |
77 } | |
78 | |
79 // Writes |size| bytes to |handle| and sets |*unblocked| to true. | 26 // Writes |size| bytes to |handle| and sets |*unblocked| to true. |
80 // Used as a crude timeout mechanism by ReadData(). | 27 // Used as a crude timeout mechanism by ReadData(). |
81 void UnblockPipe(HANDLE handle, DWORD size, bool* unblocked) { | 28 void UnblockPipe(HANDLE handle, DWORD size, bool* unblocked) { |
82 std::string unblock_data(size, '\0'); | 29 std::string unblock_data(size, '\0'); |
83 // Unblock the ReadFile in TestServer::WaitToStart by writing to the pipe. | 30 // Unblock the ReadFile in TestServer::WaitToStart by writing to the pipe. |
84 // Make sure the call succeeded, otherwise we are very likely to hang. | 31 // Make sure the call succeeded, otherwise we are very likely to hang. |
85 DWORD bytes_written = 0; | 32 DWORD bytes_written = 0; |
86 LOG(WARNING) << "Timeout reached; unblocking pipe by writing " | 33 LOG(WARNING) << "Timeout reached; unblocking pipe by writing " |
87 << size << " bytes"; | 34 << size << " bytes"; |
88 CHECK(WriteFile(handle, unblock_data.data(), size, &bytes_written, | 35 CHECK(WriteFile(handle, unblock_data.data(), size, &bytes_written, |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 // | 119 // |
173 // "64-bit versions of Windows use 32-bit handles for | 120 // "64-bit versions of Windows use 32-bit handles for |
174 // interoperability. When sharing a handle between 32-bit and 64-bit | 121 // interoperability. When sharing a handle between 32-bit and 64-bit |
175 // applications, only the lower 32 bits are significant, so it is | 122 // applications, only the lower 32 bits are significant, so it is |
176 // safe to truncate the handle (when passing it from 64-bit to | 123 // safe to truncate the handle (when passing it from 64-bit to |
177 // 32-bit) or sign-extend the handle (when passing it from 32-bit to | 124 // 32-bit) or sign-extend the handle (when passing it from 32-bit to |
178 // 64-bit)." | 125 // 64-bit)." |
179 python_command.AppendArg("--startup-pipe=" + | 126 python_command.AppendArg("--startup-pipe=" + |
180 base::IntToString(reinterpret_cast<uintptr_t>(child_write))); | 127 base::IntToString(reinterpret_cast<uintptr_t>(child_write))); |
181 | 128 |
182 if (!LaunchTestServerAsJob(python_command, | 129 job_handle_.Set(CreateJobObject(NULL, NULL)); |
183 true, | 130 if (!job_handle_.IsValid()) { |
184 &process_handle_, | 131 LOG(ERROR) << "Could not create JobObject."; |
185 &job_handle_)) { | 132 return false; |
| 133 } |
| 134 |
| 135 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; |
| 136 limit_info.BasicLimitInformation.LimitFlags = |
| 137 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; |
| 138 if (0 == SetInformationJobObject(job_handle_.Get(), |
| 139 JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info))) { |
| 140 LOG(ERROR) << "Could not SetInformationJobObject."; |
| 141 return false; |
| 142 } |
| 143 |
| 144 base::LaunchOptions launch_options; |
| 145 launch_options.inherit_handles = true; |
| 146 launch_options.job_handle = job_handle_.Get(); |
| 147 if (!base::LaunchProcess(python_command, launch_options, &process_handle_)) { |
186 LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString(); | 148 LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString(); |
187 return false; | 149 return false; |
188 } | 150 } |
189 | 151 |
190 return true; | 152 return true; |
191 } | 153 } |
192 | 154 |
193 bool TestServer::WaitToStart() { | 155 bool TestServer::WaitToStart() { |
194 base::win::ScopedHandle read_fd(child_read_fd_.Take()); | 156 base::win::ScopedHandle read_fd(child_read_fd_.Take()); |
195 base::win::ScopedHandle write_fd(child_write_fd_.Take()); | 157 base::win::ScopedHandle write_fd(child_write_fd_.Take()); |
(...skipping 14 matching lines...) Expand all Loading... |
210 | 172 |
211 if (!ParseServerData(server_data)) { | 173 if (!ParseServerData(server_data)) { |
212 LOG(ERROR) << "Could not parse server_data: " << server_data; | 174 LOG(ERROR) << "Could not parse server_data: " << server_data; |
213 return false; | 175 return false; |
214 } | 176 } |
215 | 177 |
216 return true; | 178 return true; |
217 } | 179 } |
218 | 180 |
219 } // namespace net | 181 } // namespace net |
OLD | NEW |