Suppression for crbug/241044.
[chromium-blink-merge.git] / chrome / test / chromedriver / server / chromedriver_server.cc
blobe22e4b7453b46d731eab650d696628d2f8893ea3
1 // Copyright (c) 2013 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.
5 #include <cstdio>
6 #include <iostream>
7 #include <string>
8 #include <vector>
10 #include "base/at_exit.h"
11 #include "base/command_line.h"
12 #include "base/file_util.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "chrome/test/chromedriver/chrome/version.h"
18 #include "chrome/test/chromedriver/command_executor_impl.h"
19 #include "chrome/test/chromedriver/server/http_handler.h"
20 #include "chrome/test/chromedriver/server/http_response.h"
21 #include "third_party/mongoose/mongoose.h"
23 namespace {
25 void ReadRequestBody(const struct mg_request_info* const request_info,
26 struct mg_connection* const connection,
27 std::string* request_body) {
28 int content_length = 0;
29 // 64 maximum header count hard-coded in mongoose.h
30 for (int header_index = 0; header_index < 64; ++header_index) {
31 if (request_info->http_headers[header_index].name == NULL) {
32 break;
34 if (strcmp(request_info->http_headers[header_index].name,
35 "Content-Length") == 0) {
36 base::StringToInt(
37 request_info->http_headers[header_index].value, &content_length);
38 break;
41 if (content_length > 0) {
42 request_body->resize(content_length);
43 int bytes_read = 0;
44 while (bytes_read < content_length) {
45 bytes_read += mg_read(connection,
46 &(*request_body)[bytes_read],
47 content_length - bytes_read);
52 struct MongooseUserData {
53 HttpHandler* handler;
54 base::WaitableEvent* shutdown_event;
57 void* ProcessHttpRequest(mg_event event_raised,
58 struct mg_connection* connection,
59 const struct mg_request_info* request_info) {
60 if (event_raised != MG_NEW_REQUEST)
61 return reinterpret_cast<void*>(false);
62 MongooseUserData* user_data =
63 reinterpret_cast<MongooseUserData*>(request_info->user_data);
65 std::string method_str = request_info->request_method;
66 HttpMethod method = kGet;
67 if (method_str == "PUT" || method_str == "POST")
68 method = kPost;
69 else if (method_str == "DELETE")
70 method = kDelete;
71 std::string body;
72 if (method == kPost)
73 ReadRequestBody(request_info, connection, &body);
75 HttpRequest request(method, request_info->uri, body);
76 LOG(INFO) << "Handling request: "
77 << std::string(request_info->uri) << " " << body;
79 HttpResponse response;
80 user_data->handler->Handle(request, &response);
81 LOG(INFO) << "Done handling request: "
82 << response.status() << " " << response.body();
84 // Don't allow HTTP keep alive.
85 response.AddHeader("connection", "close");
86 std::string data;
87 response.GetData(&data);
88 mg_write(connection, data.data(), data.length());
89 if (user_data->handler->ShouldShutdown(request))
90 user_data->shutdown_event->Signal();
91 return reinterpret_cast<void*>(true);
94 void MakeMongooseOptions(const std::string& port,
95 int http_threads,
96 std::vector<std::string>* out_options) {
97 out_options->push_back("listening_ports");
98 out_options->push_back(port);
99 out_options->push_back("enable_keep_alive");
100 out_options->push_back("no");
101 out_options->push_back("num_threads");
102 out_options->push_back(base::IntToString(http_threads));
105 } // namespace
107 int main(int argc, char *argv[]) {
108 CommandLine::Init(argc, argv);
110 base::AtExitManager exit;
111 CommandLine* cmd_line = CommandLine::ForCurrentProcess();
113 // Parse command line flags.
114 std::string port = "9515";
115 std::string url_base;
116 int http_threads = 4;
117 base::FilePath log_path;
118 if (cmd_line->HasSwitch("port"))
119 port = cmd_line->GetSwitchValueASCII("port");
120 if (cmd_line->HasSwitch("url-base"))
121 url_base = cmd_line->GetSwitchValueASCII("url-base");
122 if (url_base.empty() || url_base[0] != '/')
123 url_base = "/" + url_base;
124 if (url_base[url_base.length() - 1] != '/')
125 url_base = url_base + "/";
126 if (cmd_line->HasSwitch("http-threads")) {
127 if (!base::StringToInt(cmd_line->GetSwitchValueASCII("http-threads"),
128 &http_threads)) {
129 printf("'http-threads' option must be an integer\n");
130 return 1;
133 if (cmd_line->HasSwitch("log-path")) {
134 log_path = cmd_line->GetSwitchValuePath("log-path");
135 } else {
136 base::FilePath::StringType log_name(FILE_PATH_LITERAL("chromedriver.log"));
137 log_path = base::FilePath(log_name);
138 file_util::ScopedFILE file(file_util::OpenFile(log_path, "w"));
139 base::FilePath temp_dir;
140 if (!file.get() && file_util::GetTempDir(&temp_dir))
141 log_path = temp_dir.Append(log_name);
144 if (!log_path.IsAbsolute()) {
145 base::FilePath cwd;
146 if (file_util::GetCurrentDirectory(&cwd))
147 log_path = cwd.Append(log_path);
149 bool success = InitLogging(
150 log_path.value().c_str(),
151 logging::LOG_ONLY_TO_FILE,
152 logging::DONT_LOCK_LOG_FILE,
153 logging::DELETE_OLD_LOG_FILE,
154 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
155 if (!success) {
156 PLOG(ERROR) << "Unable to initialize logging";
158 logging::SetLogItems(false, // enable_process_id
159 false, // enable_thread_id
160 true, // enable_timestamp
161 false); // enable_tickcount
162 if (cmd_line->HasSwitch("verbose")) {
163 logging::SetMinLogLevel(logging::LOG_VERBOSE);
166 scoped_ptr<CommandExecutor> executor(new CommandExecutorImpl());
167 HttpHandler handler(executor.Pass(), HttpHandler::CreateCommandMap(),
168 url_base);
169 base::WaitableEvent shutdown_event(false, false);
170 MongooseUserData user_data = { &handler, &shutdown_event };
172 std::vector<std::string> args;
173 MakeMongooseOptions(port, http_threads, &args);
174 scoped_ptr<const char*[]> options(new const char*[args.size() + 1]);
175 for (size_t i = 0; i < args.size(); ++i) {
176 options[i] = args[i].c_str();
178 options[args.size()] = NULL;
180 struct mg_context* ctx = mg_start(&ProcessHttpRequest,
181 &user_data,
182 options.get());
183 if (ctx == NULL) {
184 printf("Port already in use. Exiting...\n");
185 return 1;
188 if (!cmd_line->HasSwitch("silent")) {
189 std::cout << "Started ChromeDriver" << std::endl
190 << "port=" << port << std::endl
191 << "version=" << std::string(kChromeDriverVersion) << std::endl
192 << "log=" << log_path.value() << std::endl;
194 if (!cmd_line->HasSwitch("verbose")) {
195 fclose(stdout);
196 fclose(stderr);
199 // Run until we receive command to shutdown.
200 shutdown_event.Wait();
202 return 0;