test_server_win.cc revision a8d393aaf9718c42d29078685fc0b94add05b863
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/test/test_server.h" 6 7#include <windows.h> 8#include <wincrypt.h> 9 10#include "base/base_paths.h" 11#include "base/file_util.h" 12#include "base/path_service.h" 13#include "base/string_number_conversions.h" 14#include "base/string_util.h" 15#include "base/utf_string_conversions.h" 16 17#pragma comment(lib, "crypt32.lib") 18 19namespace { 20 21bool LaunchTestServerAsJob(const std::wstring& cmdline, 22 bool start_hidden, 23 base::ProcessHandle* process_handle, 24 ScopedHandle* job_handle) { 25 // Launch test server process. 26 STARTUPINFO startup_info = {0}; 27 startup_info.cb = sizeof(startup_info); 28 startup_info.dwFlags = STARTF_USESHOWWINDOW; 29 startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW; 30 PROCESS_INFORMATION process_info; 31 32 // If this code is run under a debugger, the test server process is 33 // automatically associated with a job object created by the debugger. 34 // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this. 35 if (!CreateProcess(NULL, 36 const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, 37 TRUE, CREATE_BREAKAWAY_FROM_JOB, NULL, NULL, 38 &startup_info, &process_info)) { 39 LOG(ERROR) << "Could not create process."; 40 return false; 41 } 42 CloseHandle(process_info.hThread); 43 44 // If the caller wants the process handle, we won't close it. 45 if (process_handle) { 46 *process_handle = process_info.hProcess; 47 } else { 48 CloseHandle(process_info.hProcess); 49 } 50 51 // Create a JobObject and associate the test server process with it. 52 job_handle->Set(CreateJobObject(NULL, NULL)); 53 if (!job_handle->IsValid()) { 54 LOG(ERROR) << "Could not create JobObject."; 55 return false; 56 } else { 57 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; 58 limit_info.BasicLimitInformation.LimitFlags = 59 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; 60 if (0 == SetInformationJobObject(job_handle->Get(), 61 JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info))) { 62 LOG(ERROR) << "Could not SetInformationJobObject."; 63 return false; 64 } 65 if (0 == AssignProcessToJobObject(job_handle->Get(), 66 process_info.hProcess)) { 67 LOG(ERROR) << "Could not AssignProcessToObject."; 68 return false; 69 } 70 } 71 return true; 72} 73 74} // namespace 75 76namespace net { 77bool TestServer::LaunchPython(const FilePath& testserver_path) { 78 FilePath python_exe; 79 if (!PathService::Get(base::DIR_SOURCE_ROOT, &python_exe)) 80 return false; 81 python_exe = python_exe 82 .Append(FILE_PATH_LITERAL("third_party")) 83 .Append(FILE_PATH_LITERAL("python_24")) 84 .Append(FILE_PATH_LITERAL("python.exe")); 85 86 std::wstring command_line = 87 L"\"" + python_exe.value() + L"\" " + 88 L"\"" + testserver_path.value() + 89 L"\" --port=" + ASCIIToWide(base::IntToString(host_port_pair_.port())) + 90 L" --data-dir=\"" + document_root_.value() + L"\""; 91 92 if (type_ == TYPE_FTP) 93 command_line.append(L" -f"); 94 95 FilePath certificate_path(GetCertificatePath()); 96 if (!certificate_path.value().empty()) { 97 if (!file_util::PathExists(certificate_path)) { 98 LOG(ERROR) << "Certificate path " << certificate_path.value() 99 << " doesn't exist. Can't launch https server."; 100 return false; 101 } 102 command_line.append(L" --https=\""); 103 command_line.append(certificate_path.value()); 104 command_line.append(L"\""); 105 } 106 107 if (type_ == TYPE_HTTPS_CLIENT_AUTH) 108 command_line.append(L" --ssl-client-auth"); 109 110 HANDLE child_read = NULL; 111 HANDLE child_write = NULL; 112 if (!CreatePipe(&child_read, &child_write, NULL, 0)) { 113 PLOG(ERROR) << "Failed to create pipe"; 114 return false; 115 } 116 child_fd_.Set(child_read); 117 ScopedHandle scoped_child_write(child_write); 118 119 // Have the child inherit the write half. 120 if (!SetHandleInformation(child_write, HANDLE_FLAG_INHERIT, 121 HANDLE_FLAG_INHERIT)) { 122 PLOG(ERROR) << "Failed to enable pipe inheritance"; 123 return false; 124 } 125 126 // Pass the handle on the command-line. Although HANDLE is a 127 // pointer, truncating it on 64-bit machines is okay. See 128 // http://msdn.microsoft.com/en-us/library/aa384203.aspx 129 // 130 // "64-bit versions of Windows use 32-bit handles for 131 // interoperability. When sharing a handle between 32-bit and 64-bit 132 // applications, only the lower 32 bits are significant, so it is 133 // safe to truncate the handle (when passing it from 64-bit to 134 // 32-bit) or sign-extend the handle (when passing it from 32-bit to 135 // 64-bit)." 136 command_line.append( 137 L" --startup-pipe=" + 138 ASCIIToWide(base::IntToString(reinterpret_cast<uintptr_t>(child_write)))); 139 140 if (!LaunchTestServerAsJob(command_line, 141 true, 142 &process_handle_, 143 &job_handle_)) { 144 LOG(ERROR) << "Failed to launch " << command_line; 145 return false; 146 } 147 148 return true; 149} 150 151bool TestServer::WaitToStart() { 152 char buf[8]; 153 DWORD bytes_read; 154 BOOL result = ReadFile(child_fd_, buf, sizeof(buf), &bytes_read, NULL); 155 child_fd_.Close(); 156 return result && bytes_read > 0; 157} 158 159bool TestServer::CheckCATrusted() { 160 HCERTSTORE cert_store = CertOpenSystemStore(NULL, L"ROOT"); 161 if (!cert_store) { 162 LOG(ERROR) << " could not open trusted root CA store"; 163 return false; 164 } 165 PCCERT_CONTEXT cert = 166 CertFindCertificateInStore(cert_store, 167 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 168 0, 169 CERT_FIND_ISSUER_STR, 170 L"Test CA", 171 NULL); 172 if (cert) 173 CertFreeCertificateContext(cert); 174 CertCloseStore(cert_store, 0); 175 176 if (!cert) { 177 LOG(ERROR) << " TEST CONFIGURATION ERROR: you need to import the test ca " 178 "certificate to your trusted roots for this test to work. " 179 "For more info visit:\n" 180 "http://dev.chromium.org/developers/testing\n"; 181 return false; 182 } 183 184 return true; 185} 186 187} // namespace net 188