Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / test / chromedriver / server / chromedriver_server.cc
blob09f0bbdccdf11fcbace84b3d363f78062fcb16ca
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 <stdio.h>
6 #include <locale>
7 #include <string>
8 #include <vector>
10 #include "base/at_exit.h"
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/run_loop.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/synchronization/waitable_event.h"
24 #include "base/threading/thread.h"
25 #include "base/threading/thread_local.h"
26 #include "chrome/test/chromedriver/logging.h"
27 #include "chrome/test/chromedriver/net/port_server.h"
28 #include "chrome/test/chromedriver/server/http_handler.h"
29 #include "chrome/test/chromedriver/version.h"
30 #include "net/base/ip_endpoint.h"
31 #include "net/base/net_errors.h"
32 #include "net/server/http_server.h"
33 #include "net/server/http_server_request_info.h"
34 #include "net/server/http_server_response_info.h"
35 #include "net/socket/tcp_listen_socket.h"
37 namespace {
39 typedef base::Callback<
40 void(const net::HttpServerRequestInfo&, const HttpResponseSenderFunc&)>
41 HttpRequestHandlerFunc;
43 class HttpServer : public net::HttpServer::Delegate {
44 public:
45 explicit HttpServer(const HttpRequestHandlerFunc& handle_request_func)
46 : handle_request_func_(handle_request_func),
47 weak_factory_(this) {}
49 virtual ~HttpServer() {}
51 bool Start(int port) {
52 server_ = new net::HttpServer(
53 net::TCPListenSocketFactory("0.0.0.0", port), this);
54 net::IPEndPoint address;
55 return server_->GetLocalAddress(&address) == net::OK;
58 // Overridden from net::HttpServer::Delegate:
59 virtual void OnHttpRequest(int connection_id,
60 const net::HttpServerRequestInfo& info) OVERRIDE {
61 handle_request_func_.Run(
62 info,
63 base::Bind(&HttpServer::OnResponse,
64 weak_factory_.GetWeakPtr(),
65 connection_id));
67 virtual void OnWebSocketRequest(
68 int connection_id,
69 const net::HttpServerRequestInfo& info) OVERRIDE {}
70 virtual void OnWebSocketMessage(int connection_id,
71 const std::string& data) OVERRIDE {}
72 virtual void OnClose(int connection_id) OVERRIDE {}
74 private:
75 void OnResponse(int connection_id,
76 scoped_ptr<net::HttpServerResponseInfo> response) {
77 // Don't support keep-alive, since there's no way to detect if the
78 // client is HTTP/1.0. In such cases, the client may hang waiting for
79 // the connection to close (e.g., python 2.7 urllib).
80 response->AddHeader("Connection", "close");
81 server_->SendResponse(connection_id, *response);
82 server_->Close(connection_id);
85 HttpRequestHandlerFunc handle_request_func_;
86 scoped_refptr<net::HttpServer> server_;
87 base::WeakPtrFactory<HttpServer> weak_factory_; // Should be last.
90 void SendResponseOnCmdThread(
91 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
92 const HttpResponseSenderFunc& send_response_on_io_func,
93 scoped_ptr<net::HttpServerResponseInfo> response) {
94 io_task_runner->PostTask(
95 FROM_HERE, base::Bind(send_response_on_io_func, base::Passed(&response)));
98 void HandleRequestOnCmdThread(
99 HttpHandler* handler,
100 const net::HttpServerRequestInfo& request,
101 const HttpResponseSenderFunc& send_response_func) {
102 handler->Handle(request, send_response_func);
105 void HandleRequestOnIOThread(
106 const scoped_refptr<base::SingleThreadTaskRunner>& cmd_task_runner,
107 const HttpRequestHandlerFunc& handle_request_on_cmd_func,
108 const net::HttpServerRequestInfo& request,
109 const HttpResponseSenderFunc& send_response_func) {
110 cmd_task_runner->PostTask(
111 FROM_HERE,
112 base::Bind(handle_request_on_cmd_func,
113 request,
114 base::Bind(&SendResponseOnCmdThread,
115 base::MessageLoopProxy::current(),
116 send_response_func)));
119 base::LazyInstance<base::ThreadLocalPointer<HttpServer> >
120 lazy_tls_server = LAZY_INSTANCE_INITIALIZER;
122 void StopServerOnIOThread() {
123 // Note, |server| may be NULL.
124 HttpServer* server = lazy_tls_server.Pointer()->Get();
125 lazy_tls_server.Pointer()->Set(NULL);
126 delete server;
129 void StartServerOnIOThread(int port,
130 const HttpRequestHandlerFunc& handle_request_func) {
131 scoped_ptr<HttpServer> temp_server(new HttpServer(handle_request_func));
132 if (!temp_server->Start(port)) {
133 printf("Port not available. Exiting...\n");
134 exit(1);
136 lazy_tls_server.Pointer()->Set(temp_server.release());
139 void RunServer(int port,
140 const std::string& url_base,
141 int adb_port,
142 scoped_ptr<PortServer> port_server) {
143 base::Thread io_thread("ChromeDriver IO");
144 CHECK(io_thread.StartWithOptions(
145 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
147 base::MessageLoop cmd_loop;
148 base::RunLoop cmd_run_loop;
149 HttpHandler handler(cmd_run_loop.QuitClosure(),
150 io_thread.message_loop_proxy(),
151 url_base,
152 adb_port,
153 port_server.Pass());
154 HttpRequestHandlerFunc handle_request_func =
155 base::Bind(&HandleRequestOnCmdThread, &handler);
157 io_thread.message_loop()
158 ->PostTask(FROM_HERE,
159 base::Bind(&StartServerOnIOThread,
160 port,
161 base::Bind(&HandleRequestOnIOThread,
162 cmd_loop.message_loop_proxy(),
163 handle_request_func)));
164 // Run the command loop. This loop is quit after the response for a shutdown
165 // request is posted to the IO loop. After the command loop quits, a task
166 // is posted to the IO loop to stop the server. Lastly, the IO thread is
167 // destroyed, which waits until all pending tasks have been completed.
168 // This assumes the response is sent synchronously as part of the IO task.
169 cmd_run_loop.Run();
170 io_thread.message_loop()
171 ->PostTask(FROM_HERE, base::Bind(&StopServerOnIOThread));
174 } // namespace
176 int main(int argc, char *argv[]) {
177 CommandLine::Init(argc, argv);
179 base::AtExitManager at_exit;
180 CommandLine* cmd_line = CommandLine::ForCurrentProcess();
182 #if defined(OS_LINUX)
183 // Select the locale from the environment by passing an empty string instead
184 // of the default "C" locale. This is particularly needed for the keycode
185 // conversion code to work.
186 std::setlocale(LC_ALL, "");
187 #endif
189 // Parse command line flags.
190 int port = 9515;
191 int adb_port = 5037;
192 std::string url_base;
193 scoped_ptr<PortServer> port_server;
194 if (cmd_line->HasSwitch("h") || cmd_line->HasSwitch("help")) {
195 std::string options;
196 const char* kOptionAndDescriptions[] = {
197 "port=PORT", "port to listen on",
198 "adb-port=PORT", "adb server port",
199 "log-path=FILE", "write server log to file instead of stderr, "
200 "increases log level to INFO",
201 "verbose", "log verbosely",
202 "silent", "log nothing",
203 "url-base", "base URL path prefix for commands, e.g. wd/url",
204 "port-server", "address of server to contact for reserving a port",
206 for (size_t i = 0; i < arraysize(kOptionAndDescriptions) - 1; i += 2) {
207 options += base::StringPrintf(
208 " --%-30s%s\n",
209 kOptionAndDescriptions[i], kOptionAndDescriptions[i + 1]);
211 printf("Usage: %s [OPTIONS]\n\nOptions\n%s", argv[0], options.c_str());
212 return 0;
214 if (cmd_line->HasSwitch("port")) {
215 if (!base::StringToInt(cmd_line->GetSwitchValueASCII("port"), &port)) {
216 printf("Invalid port. Exiting...\n");
217 return 1;
220 if (cmd_line->HasSwitch("adb-port")) {
221 if (!base::StringToInt(cmd_line->GetSwitchValueASCII("adb-port"),
222 &adb_port)) {
223 printf("Invalid adb-port. Exiting...\n");
224 return 1;
227 if (cmd_line->HasSwitch("port-server")) {
228 #if defined(OS_LINUX)
229 std::string address = cmd_line->GetSwitchValueASCII("port-server");
230 if (address.empty() || address[0] != '@') {
231 printf("Invalid port-server. Exiting...\n");
232 return 1;
234 std::string path;
235 // First character of path is \0 to use Linux's abstract namespace.
236 path.push_back(0);
237 path += address.substr(1);
238 port_server.reset(new PortServer(path));
239 #else
240 printf("Warning: port-server not implemented for this platform.\n");
241 #endif
243 if (cmd_line->HasSwitch("url-base"))
244 url_base = cmd_line->GetSwitchValueASCII("url-base");
245 if (url_base.empty() || url_base[0] != '/')
246 url_base = "/" + url_base;
247 if (url_base[url_base.length() - 1] != '/')
248 url_base = url_base + "/";
249 if (!cmd_line->HasSwitch("silent")) {
250 printf(
251 "Starting ChromeDriver (v%s) on port %d\n", kChromeDriverVersion, port);
252 fflush(stdout);
255 if (!InitLogging()) {
256 printf("Unable to initialize logging. Exiting...\n");
257 return 1;
259 RunServer(port, url_base, adb_port, port_server.Pass());
260 return 0;