OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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 <stdio.h> | 5 #include <stdio.h> |
6 #include <string> | 6 #include <string> |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/at_exit.h" | 9 #include "base/at_exit.h" |
| 10 #include "base/bind.h" |
10 #include "base/command_line.h" | 11 #include "base/command_line.h" |
11 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
12 #include "base/logging.h" | 13 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/message_loop/message_loop.h" |
| 16 #include "base/run_loop.h" |
14 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
15 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
16 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
17 #include "base/synchronization/waitable_event.h" | 20 #include "base/synchronization/waitable_event.h" |
| 21 #include "base/threading/thread.h" |
18 #include "chrome/test/chromedriver/chrome/log.h" | 22 #include "chrome/test/chromedriver/chrome/log.h" |
19 #include "chrome/test/chromedriver/chrome/version.h" | 23 #include "chrome/test/chromedriver/chrome/version.h" |
20 #include "chrome/test/chromedriver/server/http_handler.h" | 24 #include "chrome/test/chromedriver/server/http_handler.h" |
21 #include "chrome/test/chromedriver/server/http_response.h" | 25 #include "chrome/test/chromedriver/server/http_response.h" |
22 #include "net/server/http_server_request_info.h" | 26 #include "net/server/http_server_request_info.h" |
23 #include "third_party/mongoose/mongoose.h" | 27 #include "third_party/mongoose/mongoose.h" |
24 | 28 |
25 #if defined(OS_POSIX) | 29 #if defined(OS_POSIX) |
26 #include <fcntl.h> | 30 #include <fcntl.h> |
27 #include <unistd.h> | 31 #include <unistd.h> |
28 #endif | 32 #endif |
29 | 33 |
30 namespace { | 34 namespace { |
31 | 35 |
| 36 void SendHttpResponse(bool shutdown, |
| 37 const HttpResponseSenderFunc& send_response_func, |
| 38 scoped_ptr<HttpResponse> response) { |
| 39 send_response_func.Run(response.Pass()); |
| 40 if (shutdown) |
| 41 base::MessageLoop::current()->QuitWhenIdle(); |
| 42 } |
| 43 |
| 44 void HandleHttpRequest(HttpHandler* handler, |
| 45 const net::HttpServerRequestInfo& request, |
| 46 const HttpResponseSenderFunc& send_response_func) { |
| 47 handler->Handle(request, |
| 48 base::Bind(&SendHttpResponse, |
| 49 handler->ShouldShutdown(request), |
| 50 send_response_func)); |
| 51 } |
| 52 |
32 void ReadRequestBody(const struct mg_request_info* const request_info, | 53 void ReadRequestBody(const struct mg_request_info* const request_info, |
33 struct mg_connection* const connection, | 54 struct mg_connection* const connection, |
34 std::string* request_body) { | 55 std::string* request_body) { |
35 int content_length = 0; | 56 int content_length = 0; |
36 // 64 maximum header count hard-coded in mongoose.h | 57 // 64 maximum header count hard-coded in mongoose.h |
37 for (int header_index = 0; header_index < 64; ++header_index) { | 58 for (int header_index = 0; header_index < 64; ++header_index) { |
38 if (request_info->http_headers[header_index].name == NULL) { | 59 if (request_info->http_headers[header_index].name == NULL) { |
39 break; | 60 break; |
40 } | 61 } |
41 if (LowerCaseEqualsASCII(request_info->http_headers[header_index].name, | 62 if (LowerCaseEqualsASCII(request_info->http_headers[header_index].name, |
42 "content-length")) { | 63 "content-length")) { |
43 base::StringToInt( | 64 base::StringToInt( |
44 request_info->http_headers[header_index].value, &content_length); | 65 request_info->http_headers[header_index].value, &content_length); |
45 break; | 66 break; |
46 } | 67 } |
47 } | 68 } |
48 if (content_length > 0) { | 69 if (content_length > 0) { |
49 request_body->resize(content_length); | 70 request_body->resize(content_length); |
50 int bytes_read = 0; | 71 int bytes_read = 0; |
51 while (bytes_read < content_length) { | 72 while (bytes_read < content_length) { |
52 bytes_read += mg_read(connection, | 73 bytes_read += mg_read(connection, |
53 &(*request_body)[bytes_read], | 74 &(*request_body)[bytes_read], |
54 content_length - bytes_read); | 75 content_length - bytes_read); |
55 } | 76 } |
56 } | 77 } |
57 } | 78 } |
58 | 79 |
| 80 typedef base::Callback< |
| 81 void(const net::HttpServerRequestInfo&, const HttpResponseSenderFunc&)> |
| 82 HttpRequestHandlerFunc; |
| 83 |
59 struct MongooseUserData { | 84 struct MongooseUserData { |
60 HttpHandler* handler; | 85 base::SingleThreadTaskRunner* cmd_task_runner; |
61 base::WaitableEvent* shutdown_event; | 86 HttpRequestHandlerFunc* handler_func; |
62 }; | 87 }; |
63 | 88 |
| 89 void DoneProcessing(base::WaitableEvent* event, |
| 90 scoped_ptr<HttpResponse>* response_to_set, |
| 91 scoped_ptr<HttpResponse> response) { |
| 92 *response_to_set = response.Pass(); |
| 93 event->Signal(); |
| 94 } |
| 95 |
64 void* ProcessHttpRequest(mg_event event_raised, | 96 void* ProcessHttpRequest(mg_event event_raised, |
65 struct mg_connection* connection, | 97 struct mg_connection* connection, |
66 const struct mg_request_info* request_info) { | 98 const struct mg_request_info* request_info) { |
67 if (event_raised != MG_NEW_REQUEST) | 99 if (event_raised != MG_NEW_REQUEST) |
68 return reinterpret_cast<void*>(false); | 100 return reinterpret_cast<void*>(false); |
69 MongooseUserData* user_data = | 101 MongooseUserData* user_data = |
70 reinterpret_cast<MongooseUserData*>(request_info->user_data); | 102 reinterpret_cast<MongooseUserData*>(request_info->user_data); |
71 | 103 |
72 net::HttpServerRequestInfo request; | 104 net::HttpServerRequestInfo request; |
73 request.method = request_info->request_method; | 105 request.method = request_info->request_method; |
74 request.path = request_info->uri; | 106 request.path = request_info->uri; |
75 ReadRequestBody(request_info, connection, &request.data); | 107 ReadRequestBody(request_info, connection, &request.data); |
76 | 108 |
77 HttpResponse response; | 109 base::WaitableEvent event(false, false); |
78 user_data->handler->Handle(request, &response); | 110 scoped_ptr<HttpResponse> response; |
| 111 user_data->cmd_task_runner |
| 112 ->PostTask(FROM_HERE, |
| 113 base::Bind(*user_data->handler_func, |
| 114 request, |
| 115 base::Bind(&DoneProcessing, &event, &response))); |
| 116 event.Wait(); |
79 | 117 |
80 // Don't allow HTTP keep alive. | 118 // Don't allow HTTP keep alive. |
81 response.AddHeader("connection", "close"); | 119 response->AddHeader("connection", "close"); |
82 std::string data; | 120 std::string data; |
83 response.GetData(&data); | 121 response->GetData(&data); |
84 mg_write(connection, data.data(), data.length()); | 122 mg_write(connection, data.data(), data.length()); |
85 if (user_data->handler->ShouldShutdown(request)) | |
86 user_data->shutdown_event->Signal(); | |
87 return reinterpret_cast<void*>(true); | 123 return reinterpret_cast<void*>(true); |
88 } | 124 } |
89 | 125 |
90 void MakeMongooseOptions(const std::string& port, | 126 void MakeMongooseOptions(const std::string& port, |
91 int http_threads, | 127 int http_threads, |
92 std::vector<std::string>* out_options) { | 128 std::vector<std::string>* out_options) { |
93 out_options->push_back("listening_ports"); | 129 out_options->push_back("listening_ports"); |
94 out_options->push_back(port); | 130 out_options->push_back(port); |
95 out_options->push_back("enable_keep_alive"); | 131 out_options->push_back("enable_keep_alive"); |
96 out_options->push_back("no"); | 132 out_options->push_back("no"); |
97 out_options->push_back("num_threads"); | 133 out_options->push_back("num_threads"); |
98 out_options->push_back(base::IntToString(http_threads)); | 134 out_options->push_back(base::IntToString(http_threads)); |
99 } | 135 } |
100 | 136 |
101 } // namespace | 137 } // namespace |
102 | 138 |
103 int main(int argc, char *argv[]) { | 139 int main(int argc, char *argv[]) { |
104 CommandLine::Init(argc, argv); | 140 CommandLine::Init(argc, argv); |
105 | 141 |
106 base::AtExitManager exit; | 142 base::AtExitManager at_exit; |
107 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 143 CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
108 | 144 |
109 // Parse command line flags. | 145 // Parse command line flags. |
110 std::string port = "9515"; | 146 std::string port = "9515"; |
111 std::string url_base; | 147 std::string url_base; |
112 int http_threads = 4; | 148 int http_threads = 4; |
113 base::FilePath log_path; | 149 base::FilePath log_path; |
114 Log::Level log_level = Log::kError; | 150 Log::Level log_level = Log::kError; |
115 if (cmd_line->HasSwitch("h") || cmd_line->HasSwitch("help")) { | 151 if (cmd_line->HasSwitch("h") || cmd_line->HasSwitch("help")) { |
116 std::string options; | 152 std::string options; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 if (!success) { | 204 if (!success) { |
169 PLOG(ERROR) << "Unable to initialize logging"; | 205 PLOG(ERROR) << "Unable to initialize logging"; |
170 } | 206 } |
171 logging::SetLogItems(false, // enable_process_id | 207 logging::SetLogItems(false, // enable_process_id |
172 false, // enable_thread_id | 208 false, // enable_thread_id |
173 false, // enable_timestamp | 209 false, // enable_timestamp |
174 false); // enable_tickcount | 210 false); // enable_tickcount |
175 if (!cmd_line->HasSwitch("verbose")) | 211 if (!cmd_line->HasSwitch("verbose")) |
176 logging::SetMinLogLevel(logging::LOG_FATAL); | 212 logging::SetMinLogLevel(logging::LOG_FATAL); |
177 | 213 |
| 214 base::Thread io_thread("ChromeDriver IO"); |
| 215 CHECK(io_thread.StartWithOptions( |
| 216 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))); |
| 217 |
178 scoped_ptr<Log> log(new Logger(log_level)); | 218 scoped_ptr<Log> log(new Logger(log_level)); |
179 HttpHandler handler(log.get(), url_base); | 219 HttpHandler handler(io_thread.message_loop_proxy(), log.get(), url_base); |
180 base::WaitableEvent shutdown_event(false, false); | 220 base::MessageLoop cmd_loop; |
181 MongooseUserData user_data = { &handler, &shutdown_event }; | 221 HttpRequestHandlerFunc handler_func = |
| 222 base::Bind(&HandleHttpRequest, &handler); |
| 223 MongooseUserData user_data = { cmd_loop.message_loop_proxy(), &handler_func }; |
182 | 224 |
183 std::vector<std::string> args; | 225 std::vector<std::string> args; |
184 MakeMongooseOptions(port, http_threads, &args); | 226 MakeMongooseOptions(port, http_threads, &args); |
185 scoped_ptr<const char*[]> options(new const char*[args.size() + 1]); | 227 scoped_ptr<const char*[]> options(new const char*[args.size() + 1]); |
186 for (size_t i = 0; i < args.size(); ++i) { | 228 for (size_t i = 0; i < args.size(); ++i) { |
187 options[i] = args[i].c_str(); | 229 options[i] = args[i].c_str(); |
188 } | 230 } |
189 options[args.size()] = NULL; | 231 options[args.size()] = NULL; |
190 | 232 |
191 struct mg_context* ctx = mg_start(&ProcessHttpRequest, | 233 struct mg_context* ctx = mg_start(&ProcessHttpRequest, |
(...skipping 11 matching lines...) Expand all Loading... |
203 fflush(stdout); | 245 fflush(stdout); |
204 } | 246 } |
205 | 247 |
206 #if defined(OS_POSIX) | 248 #if defined(OS_POSIX) |
207 if (!cmd_line->HasSwitch("verbose")) { | 249 if (!cmd_line->HasSwitch("verbose")) { |
208 // Close stderr on exec, so that Chrome log spew doesn't confuse users. | 250 // Close stderr on exec, so that Chrome log spew doesn't confuse users. |
209 fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC); | 251 fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC); |
210 } | 252 } |
211 #endif | 253 #endif |
212 | 254 |
213 // Run until we receive command to shutdown. | 255 base::RunLoop cmd_run_loop; |
214 shutdown_event.Wait(); | 256 cmd_run_loop.Run(); |
215 | 257 // Don't run destructors for objects passed via MongooseUserData, |
216 return 0; | 258 // because ProcessHttpRequest may be accessing them. |
| 259 // TODO(kkania): Fix when switching to net::HttpServer. |
| 260 exit(0); |
217 } | 261 } |
OLD | NEW |