1 // Copyright 2013 The Chromium Authors
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 <stdio.h>
6
7 #include <memory>
8
9 #include "base/at_exit.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_pump_type.h"
15 #include "base/run_loop.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/task/single_thread_task_executor.h"
18 #include "base/test/test_timeouts.h"
19 #include "net/test/embedded_test_server/embedded_test_server.h"
20 #include "net/test/spawned_test_server/spawned_test_server.h"
21
PrintUsage()22 static void PrintUsage() {
23 printf(
24 "run_testserver --doc-root=relpath\n"
25 " [--http|--https|--ws|--wss]\n"
26 " [--ssl-cert=ok|mismatched-name|expired]\n");
27 printf("(NOTE: relpath should be relative to the 'src' directory.\n");
28 }
29
main(int argc,const char * argv[])30 int main(int argc, const char* argv[]) {
31 base::AtExitManager at_exit_manager;
32 base::SingleThreadTaskExecutor io_task_executor(base::MessagePumpType::IO);
33
34 // Process command line
35 base::CommandLine::Init(argc, argv);
36 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
37
38 logging::LoggingSettings settings;
39 settings.logging_dest = logging::LOG_TO_ALL;
40 settings.log_file_path = FILE_PATH_LITERAL("testserver.log");
41 if (!logging::InitLogging(settings)) {
42 printf("Error: could not initialize logging. Exiting.\n");
43 return -1;
44 }
45
46 TestTimeouts::Initialize();
47
48 if (command_line->GetSwitches().empty() ||
49 command_line->HasSwitch("help")) {
50 PrintUsage();
51 return -1;
52 }
53
54 // If populated, EmbeddedTestServer is used instead of the SpawnedTestServer.
55 std::optional<net::EmbeddedTestServer::Type> embedded_test_server_type;
56
57 net::SpawnedTestServer::Type server_type;
58 if (command_line->HasSwitch("http")) {
59 embedded_test_server_type = net::EmbeddedTestServer::TYPE_HTTP;
60 } else if (command_line->HasSwitch("https")) {
61 embedded_test_server_type = net::EmbeddedTestServer::TYPE_HTTPS;
62 } else if (command_line->HasSwitch("ws")) {
63 server_type = net::SpawnedTestServer::TYPE_WS;
64 } else if (command_line->HasSwitch("wss")) {
65 server_type = net::SpawnedTestServer::TYPE_WSS;
66 } else {
67 // If no scheme switch is specified, select http or https scheme.
68 // TODO(toyoshim): Remove this estimation.
69 if (command_line->HasSwitch("ssl-cert")) {
70 embedded_test_server_type = net::EmbeddedTestServer::TYPE_HTTPS;
71 } else {
72 embedded_test_server_type = net::EmbeddedTestServer::TYPE_HTTP;
73 }
74 }
75
76 net::SpawnedTestServer::SSLOptions ssl_options;
77 net::EmbeddedTestServer::ServerCertificate server_certificate;
78 if (command_line->HasSwitch("ssl-cert")) {
79 if ((embedded_test_server_type.has_value() &&
80 *embedded_test_server_type != net::EmbeddedTestServer::TYPE_HTTPS) ||
81 (!embedded_test_server_type.has_value() &&
82 !net::SpawnedTestServer::UsingSSL(server_type))) {
83 printf("Error: --ssl-cert is specified on non-secure scheme\n");
84 PrintUsage();
85 return -1;
86 }
87 std::string cert_option = command_line->GetSwitchValueASCII("ssl-cert");
88 if (cert_option == "ok") {
89 ssl_options.server_certificate =
90 net::SpawnedTestServer::SSLOptions::CERT_OK;
91 server_certificate = net::EmbeddedTestServer::CERT_OK;
92 } else if (cert_option == "mismatched-name") {
93 ssl_options.server_certificate =
94 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
95 server_certificate = net::EmbeddedTestServer::CERT_MISMATCHED_NAME;
96 } else if (cert_option == "expired") {
97 ssl_options.server_certificate =
98 net::SpawnedTestServer::SSLOptions::CERT_EXPIRED;
99 server_certificate = net::EmbeddedTestServer::CERT_EXPIRED;
100 } else {
101 printf("Error: --ssl-cert has invalid value %s\n", cert_option.c_str());
102 PrintUsage();
103 return -1;
104 }
105 }
106
107 base::FilePath doc_root = command_line->GetSwitchValuePath("doc-root");
108 if (doc_root.empty()) {
109 printf("Error: --doc-root must be specified\n");
110 PrintUsage();
111 return -1;
112 }
113
114 base::FilePath full_path =
115 net::test_server::EmbeddedTestServer::GetFullPathFromSourceDirectory(
116 doc_root);
117 if (!base::DirectoryExists(full_path)) {
118 printf("Error: invalid doc root: \"%s\" does not exist!\n",
119 base::UTF16ToUTF8(full_path.LossyDisplayName()).c_str());
120 return -1;
121 }
122
123 // Use EmbeddedTestServer, if it supports the provided configuration.
124 if (embedded_test_server_type.has_value()) {
125 net::EmbeddedTestServer embedded_test_server(*embedded_test_server_type);
126 if (*embedded_test_server_type == net::EmbeddedTestServer::TYPE_HTTPS) {
127 embedded_test_server.SetSSLConfig(server_certificate);
128 }
129
130 embedded_test_server.AddDefaultHandlers(doc_root);
131 if (!embedded_test_server.Start()) {
132 printf("Error: failed to start embedded test server. Exiting.\n");
133 return -1;
134 }
135
136 printf("Embedded test server running at %s (type ctrl+c to exit)\n",
137 embedded_test_server.host_port_pair().ToString().c_str());
138
139 base::RunLoop().Run();
140 return 0;
141 }
142
143 // Otherwise, use the SpawnedTestServer.
144 std::unique_ptr<net::SpawnedTestServer> test_server;
145 if (net::SpawnedTestServer::UsingSSL(server_type)) {
146 test_server = std::make_unique<net::SpawnedTestServer>(
147 server_type, ssl_options, doc_root);
148 } else {
149 test_server =
150 std::make_unique<net::SpawnedTestServer>(server_type, doc_root);
151 }
152
153 if (!test_server->Start()) {
154 printf("Error: failed to start test server. Exiting.\n");
155 return -1;
156 }
157
158 printf("testserver running at %s (type ctrl+c to exit)\n",
159 test_server->host_port_pair().ToString().c_str());
160
161 base::RunLoop().Run();
162 }
163