OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "chrome/browser/google_apis/test_server/http_server.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_util.h" | |
9 #include "base/stl_util.h" | |
10 #include "base/stringprintf.h" | |
11 #include "chrome/browser/google_apis/gdata_test_util.h" | |
12 #include "chrome/browser/google_apis/test_server/http_request.h" | |
13 #include "chrome/browser/google_apis/test_server/http_response.h" | |
14 #include "content/public/browser/browser_thread.h" | |
15 #include "content/public/test/test_utils.h" | |
16 #include "net/tools/fetch/http_listen_socket.h" | |
17 | |
18 namespace drive { | |
19 namespace test_server { | |
20 | |
21 using content::BrowserThread; | |
22 | |
23 namespace { | |
24 | |
25 const int kPort = 8040; | |
26 const char kIp[] = "127.0.0.1"; | |
27 const int kRetries = 10; | |
28 | |
29 // Callback to handle requests with default predefined response for requests | |
30 // matching the address |url|. | |
31 scoped_ptr<HttpResponse> HandleDefaultRequest(const GURL& url, | |
32 const HttpResponse& response, | |
33 const HttpRequest& request) { | |
34 if (url.path() != request.url.path()) | |
35 return scoped_ptr<HttpResponse>(NULL); | |
36 return scoped_ptr<HttpResponse>(new HttpResponse(response)); | |
37 } | |
38 | |
39 } // namespace | |
40 | |
41 HttpListenSocket::HttpListenSocket(const SocketDescriptor socket_descriptor, | |
42 net::StreamListenSocket::Delegate* delegate) | |
43 : net::TCPListenSocket(socket_descriptor, delegate) { | |
44 } | |
45 | |
46 void HttpListenSocket::Listen() { | |
47 net::TCPListenSocket::Listen(); | |
48 } | |
49 | |
50 HttpListenSocket::~HttpListenSocket() { | |
51 } | |
52 | |
53 bool HttpServer::InitializeAndWaitUntilReady() { | |
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
55 | |
56 BrowserThread::PostTask( | |
57 BrowserThread::IO, | |
58 FROM_HERE, | |
59 base::Bind(&HttpServer::InitializeOnIOThread, | |
60 base::Unretained(this), | |
61 InitializeCallback())); | |
62 | |
63 // Wait for the task completion. | |
64 content::RunAllPendingInMessageLoop(BrowserThread::IO); | |
65 content::RunAllPendingInMessageLoop(); | |
66 | |
67 return Started(); | |
68 } | |
69 | |
70 void HttpServer::InitializeOnIOThread(const InitializeCallback& callback) { | |
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
72 DCHECK(!Started()); | |
73 | |
74 int retries_left = kRetries + 1; | |
75 int try_port = kPort; | |
76 | |
77 while (retries_left > 0) { | |
78 SocketDescriptor socket_descriptor = net::TCPListenSocket::CreateAndBind( | |
79 kIp, | |
80 try_port); | |
81 if (socket_descriptor != net::TCPListenSocket::kInvalidSocket) { | |
82 listen_socket_ = new HttpListenSocket(socket_descriptor, this); | |
83 listen_socket_->Listen(); | |
84 base_url_ = GURL(base::StringPrintf("http://%s:%d", kIp, try_port)); | |
85 port_ = try_port; | |
86 break; | |
87 } | |
88 retries_left--; | |
89 try_port++; | |
90 } | |
91 | |
92 if (!callback.is_null()) | |
93 callback.Run(listen_socket_.get() != NULL); | |
94 } | |
95 | |
96 HttpServer::HttpServer() | |
97 : port_(-1), | |
98 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { | |
99 } | |
100 | |
101 HttpServer::~HttpServer() { | |
102 STLDeleteContainerPairSecondPointers(connections_.begin(), | |
103 connections_.end()); | |
104 } | |
105 | |
106 void HttpServer::HandleRequest(HttpConnection* connection, | |
107 scoped_ptr<HttpRequest> request) { | |
108 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
109 | |
110 for (size_t i = 0; i < request_handlers_.size(); ++i) { | |
111 scoped_ptr<HttpResponse> response = | |
112 request_handlers_[i].Run(*request.get()); | |
113 if (response.get()) { | |
114 connection->SendResponse(response.Pass()); | |
115 return; | |
116 } | |
117 } | |
118 | |
119 LOG(WARNING) << "Request not handled. Returning 404."; | |
120 scoped_ptr<HttpResponse> not_found_response(new HttpResponse()); | |
121 not_found_response->set_code(NOT_FOUND); | |
122 connection->SendResponse(not_found_response.Pass()); | |
123 | |
124 // Drop the connection, since we do not support multiple requests per | |
125 // connection. | |
126 connections_.erase(connection->socket_.get()); | |
127 delete connection; | |
128 } | |
129 | |
130 GURL HttpServer::GetBaseURL() { | |
131 return base_url_; | |
132 } | |
133 | |
134 void HttpServer::RegisterRequestHandler( | |
135 const HandleRequestCallback& callback) { | |
136 request_handlers_.push_back(callback); | |
137 } | |
138 | |
139 GURL HttpServer::RegisterDefaultResponse( | |
140 const std::string& relative_path, | |
141 const HttpResponse& default_response) { | |
142 GURL request_url = base_url_.Resolve(relative_path); | |
143 const HandleRequestCallback callback = | |
144 base::Bind(&HandleDefaultRequest, | |
145 request_url, | |
146 default_response); | |
147 request_handlers_.push_back(callback); | |
148 | |
149 return request_url; | |
150 } | |
151 | |
152 GURL HttpServer::RegisterTextResponse( | |
153 const std::string& relative_path, | |
154 const std::string& content, | |
155 const std::string& content_type, | |
156 const ResponseCode response_code) { | |
157 HttpResponse default_response; | |
158 default_response.set_content(content); | |
159 default_response.set_content_type(content_type); | |
160 default_response.set_code(response_code); | |
161 | |
162 return RegisterDefaultResponse(relative_path, default_response); | |
163 } | |
164 | |
165 GURL HttpServer::RegisterFileResponse( | |
166 const std::string& relative_path, | |
167 const FilePath& file_path, | |
168 const std::string& content_type, | |
169 const ResponseCode response_code) { | |
170 HttpResponse default_response; | |
171 | |
172 std::string content; | |
173 const bool success = file_util::ReadFileToString( | |
174 file_path, &content); | |
175 default_response.set_content(content); | |
176 DCHECK(success) << "Failed to open the file: " << file_path.value(); | |
177 | |
178 default_response.set_content_type(content_type); | |
179 default_response.set_code(response_code); | |
180 | |
181 return RegisterDefaultResponse(relative_path, default_response); | |
182 } | |
183 | |
184 void HttpServer::DidAccept(net::StreamListenSocket* server, | |
185 net::StreamListenSocket* connection) { | |
186 HttpConnection* http_connection = new HttpConnection( | |
187 connection, | |
188 base::Bind(&HttpServer::HandleRequest, weak_factory_.GetWeakPtr())); | |
189 connections_[connection] = http_connection; | |
190 } | |
191 | |
192 void HttpServer::DidRead(net::StreamListenSocket* connection, | |
193 const char* data, | |
194 int length) { | |
195 HttpConnection* http_connection = FindConnection(connection); | |
196 if (http_connection == NULL) { | |
197 LOG(WARNING) << "Unknown connection."; | |
198 return; | |
199 } | |
200 http_connection->ReceiveData(std::string(data, length)); | |
201 } | |
202 | |
203 void HttpServer::DidClose(net::StreamListenSocket* connection) { | |
204 HttpConnection* http_connection = FindConnection(connection); | |
205 if (http_connection == NULL) { | |
206 LOG(WARNING) << "Unknown connection."; | |
207 return; | |
208 } | |
209 delete http_connection; | |
210 connections_.erase(connection); | |
211 } | |
212 | |
213 HttpConnection* HttpServer::FindConnection( | |
214 net::StreamListenSocket* socket) { | |
215 std::map<net::StreamListenSocket*, HttpConnection*>::iterator it = | |
216 connections_.find(socket); | |
217 if (it == connections_.end()) { | |
218 return NULL; | |
219 } | |
220 return it->second; | |
221 } | |
222 | |
223 } // namespace test_server | |
224 } // namespace drive | |
OLD | NEW |