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.
5 #include "chrome/browser/google_apis/test_server/http_server.h"
8 #include "base/stl_util.h"
9 #include "base/string_util.h"
10 #include "base/stringprintf.h"
11 #include "chrome/browser/google_apis/test_server/http_connection.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"
18 namespace google_apis
{
19 namespace test_server
{
21 using content::BrowserThread
;
25 const int kPort
= 8040;
26 const char kIp
[] = "127.0.0.1";
27 const int kRetries
= 10;
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 const GURL request_url
= url
.Resolve(request
.relative_url
);
35 if (url
.path() != request_url
.path())
36 return scoped_ptr
<HttpResponse
>(NULL
);
37 return scoped_ptr
<HttpResponse
>(new HttpResponse(response
));
42 HttpListenSocket::HttpListenSocket(const SocketDescriptor socket_descriptor
,
43 net::StreamListenSocket::Delegate
* delegate
)
44 : net::TCPListenSocket(socket_descriptor
, delegate
) {
45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
48 void HttpListenSocket::Listen() {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
50 net::TCPListenSocket::Listen();
53 HttpListenSocket::~HttpListenSocket() {
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
57 HttpServer::HttpServer()
59 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
63 HttpServer::~HttpServer() {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
67 bool HttpServer::InitializeAndWaitUntilReady() {
68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
70 BrowserThread::PostTask(
73 base::Bind(&HttpServer::InitializeOnIOThread
,
74 base::Unretained(this)));
76 // Wait for the task completion.
77 content::RunAllPendingInMessageLoop(BrowserThread::IO
);
82 void HttpServer::ShutdownAndWaitUntilComplete() {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
85 BrowserThread::PostTask(
88 base::Bind(&HttpServer::ShutdownOnIOThread
,
89 base::Unretained(this)));
91 // Wait for the task completion.
92 content::RunAllPendingInMessageLoop(BrowserThread::IO
);
95 void HttpServer::InitializeOnIOThread() {
96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
99 int retries_left
= kRetries
+ 1;
100 int try_port
= kPort
;
102 while (retries_left
> 0) {
103 SocketDescriptor socket_descriptor
= net::TCPListenSocket::CreateAndBind(
106 if (socket_descriptor
!= net::TCPListenSocket::kInvalidSocket
) {
107 listen_socket_
= new HttpListenSocket(socket_descriptor
, this);
108 listen_socket_
->Listen();
109 base_url_
= GURL(base::StringPrintf("http://%s:%d", kIp
, try_port
));
118 void HttpServer::ShutdownOnIOThread() {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
121 listen_socket_
= NULL
; // Release the listen socket.
122 STLDeleteContainerPairSecondPointers(connections_
.begin(),
124 connections_
.clear();
127 void HttpServer::HandleRequest(HttpConnection
* connection
,
128 scoped_ptr
<HttpRequest
> request
) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
131 for (size_t i
= 0; i
< request_handlers_
.size(); ++i
) {
132 scoped_ptr
<HttpResponse
> response
=
133 request_handlers_
[i
].Run(*request
.get());
134 if (response
.get()) {
135 connection
->SendResponse(response
.Pass());
140 LOG(WARNING
) << "Request not handled. Returning 404: "
141 << request
->relative_url
;
142 scoped_ptr
<HttpResponse
> not_found_response(new HttpResponse());
143 not_found_response
->set_code(NOT_FOUND
);
144 connection
->SendResponse(not_found_response
.Pass());
146 // Drop the connection, since we do not support multiple requests per
148 connections_
.erase(connection
->socket_
.get());
152 GURL
HttpServer::GetURL(const std::string
& relative_url
) const {
153 DCHECK(StartsWithASCII(relative_url
, "/", true /* case_sensitive */))
155 return base_url_
.Resolve(relative_url
);
158 void HttpServer::RegisterRequestHandler(
159 const HandleRequestCallback
& callback
) {
160 request_handlers_
.push_back(callback
);
163 void HttpServer::DidAccept(net::StreamListenSocket
* server
,
164 net::StreamListenSocket
* connection
) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
167 HttpConnection
* http_connection
= new HttpConnection(
169 base::Bind(&HttpServer::HandleRequest
, weak_factory_
.GetWeakPtr()));
170 connections_
[connection
] = http_connection
;
173 void HttpServer::DidRead(net::StreamListenSocket
* connection
,
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
178 HttpConnection
* http_connection
= FindConnection(connection
);
179 if (http_connection
== NULL
) {
180 LOG(WARNING
) << "Unknown connection.";
183 http_connection
->ReceiveData(std::string(data
, length
));
186 void HttpServer::DidClose(net::StreamListenSocket
* connection
) {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
189 HttpConnection
* http_connection
= FindConnection(connection
);
190 if (http_connection
== NULL
) {
191 LOG(WARNING
) << "Unknown connection.";
194 delete http_connection
;
195 connections_
.erase(connection
);
198 HttpConnection
* HttpServer::FindConnection(
199 net::StreamListenSocket
* socket
) {
200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
202 std::map
<net::StreamListenSocket
*, HttpConnection
*>::iterator it
=
203 connections_
.find(socket
);
204 if (it
== connections_
.end()) {
210 } // namespace test_server
211 } // namespace google_apis