Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Side by Side Diff: chrome/browser/google_apis/test_server/http_server.cc

Issue 11088073: HTTP server for testing Google Drive. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Moved to chrome/browser/google_apis. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/stl_util.h"
9 #include "base/file_util.h"
10 #include "base/stringprintf.h"
11 #include "chrome/browser/google_apis/test_server/http_request.h"
12 #include "chrome/browser/google_apis/test_server/http_response.h"
13 #include "chrome/browser/google_apis/gdata_test_util.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "net/tools/fetch/http_listen_socket.h"
16
17 #include <sstream>
18
19 namespace drive {
20 namespace test_server {
21
22 using content::BrowserThread;
23
24 namespace {
25
26 const int kPort = 8040;
27 const char kIp[] = "127.0.0.1";
28 const int kRetries = 10;
29
30 // Callback about success or failure in creating a server. |result| is a pointer
31 // to result passed back to HttpServer::CreateForTesting. |server| is a
32 // pointer to the created server or NULL in case of failure.
33 static void OnCreatedForTesting(HttpServer** result,
34 HttpServer* server) {
35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
36 *result = server;
37 MessageLoop::current()->Quit();
38 }
39
40 // Callback to handle requests with default predefined response for requests
41 // matching the address |url|.
42 scoped_ptr<HttpResponse> HandleDefaultRequest(const GURL& url,
43 const HttpResponse& response,
44 const HttpRequest* request) {
45 if (url.path() != request->uri.path())
46 return scoped_ptr<HttpResponse>(NULL);
47 return scoped_ptr<HttpResponse>(new HttpResponse(response));
48 }
49
50 } // namespace
51
52 HttpListenSocket::HttpListenSocket(const SocketDescriptor socket_descriptor,
53 net::StreamListenSocket::Delegate* delegate)
54 : net::TCPListenSocket(socket_descriptor, delegate) {
55 }
56
57 void HttpListenSocket::Listen() {
58 net::TCPListenSocket::Listen();
59 }
60
61 HttpListenSocket::~HttpListenSocket() {
62 }
63
64 // static
65 scoped_ptr<HttpServer> HttpServer::CreateForTesting() {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
67
68 HttpServer* result = NULL;
69 BrowserThread::PostTask(
70 BrowserThread::IO,
71 FROM_HERE,
72 base::Bind(
73 &HttpServer::CreateOnIOThread,
74 base::Bind(OnCreatedForTesting, &result)));
75
76 // Wait for the task completion.
77 MessageLoop::current()->Run();
78 return scoped_ptr<HttpServer>(result);
79 }
80
81 // static
82 void HttpServer::CreateOnIOThread(const CreateCallback& callback) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
84
85 int retries_left = kRetries + 1;
86 int try_port = kPort;
87 HttpServer* server = NULL;
88
89 while (retries_left > 0) {
90 SocketDescriptor socket_descriptor = net::TCPListenSocket::CreateAndBind(
91 kIp,
92 try_port);
93 if (socket_descriptor != net::TCPListenSocket::kInvalidSocket) {
94 server = new HttpServer(try_port, socket_descriptor);
95 break;
96 }
97 retries_left--;
98 try_port++;
99 }
100
101 BrowserThread::PostTask(BrowserThread::UI,
102 FROM_HERE,
103 base::Bind(callback, server));
104 }
105
106 HttpServer::HttpServer(int port,
107 const SocketDescriptor& socket_descriptor)
108 : listen_socket_(new HttpListenSocket(
109 socket_descriptor,
110 ALLOW_THIS_IN_INITIALIZER_LIST(this))),
111 port_(port),
112 last_unique_id_(0),
113 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
114 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
115 listen_socket_->Listen();
116 base_url_ = GURL(base::StringPrintf("http://%s:%d", kIp, port_));
117 }
118
119 HttpServer::~HttpServer() {
120 STLDeleteContainerPairSecondPointers(connections_.begin(),
121 connections_.end());
122 }
123
124 void HttpServer::HandleRequest(HttpConnection* connection,
125 scoped_ptr<HttpRequest> request) {
126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
127
128 for (size_t i = 0; i < request_handlers_.size(); ++i) {
129 scoped_ptr<HttpResponse> response =
130 request_handlers_[i].Run(request.get());
131 if (response.get()) {
132 connection->SendResponse(response.Pass());
133 return;
134 }
135 }
136
137 LOG(WARNING) << "Request not handled. Returning 404.";
138 scoped_ptr<HttpResponse> not_found_response(new HttpResponse());
139 not_found_response->code = NOT_FOUND;
140 connection->SendResponse(not_found_response.Pass());
141 }
142
143 GURL HttpServer::GetBaseURL() {
144 return base_url_;
145 }
146
147 void HttpServer::RegisterRequestHandler(
148 const HandleRequestCallback& callback) {
149 request_handlers_.push_back(callback);
150 }
151
152 GURL HttpServer::RegisterDefaultResponse(
153 const std::string& relative_path,
154 const HttpResponse& default_response) {
155 GURL request_url = base_url_.Resolve(relative_path);
156 const HandleRequestCallback callback =
157 base::Bind(&HandleDefaultRequest,
158 request_url,
159 default_response);
160 request_handlers_.push_back(callback);
161
162 return request_url;
163 }
164
165 GURL HttpServer::RegisterTextResponse(
166 const std::string& relative_path,
167 const std::string& content,
168 const std::string& content_type,
169 const ResponseCode response_code) {
170 HttpResponse default_response;
171 default_response.content = content;
172 default_response.content_type = content_type;
173 default_response.code = response_code;
174
175 return RegisterDefaultResponse(relative_path, default_response);
176 }
177
178 GURL HttpServer::RegisterFileResponse(
179 const std::string& relative_path,
180 const FilePath& file_path,
181 const std::string& content_type,
182 const ResponseCode response_code) {
183 HttpResponse default_response;
184
185 DCHECK(file_util::ReadFileToString(file_path, &default_response.content)) <<
186 "Failed to open the file: " << file_path.value();
187
188 default_response.content_type = content_type;
189 default_response.code = response_code;
190
191 return RegisterDefaultResponse(relative_path, default_response);
192 }
193
194 void HttpServer::DidAccept(net::StreamListenSocket* server,
195 net::StreamListenSocket* connection) {
196 HttpConnection* http_connection = new HttpConnection(
197 connection,
198 base::Bind(&HttpServer::HandleRequest, weak_factory_.GetWeakPtr()));
199 connections_[connection] = http_connection;
200 }
201
202 void HttpServer::DidRead(net::StreamListenSocket* connection,
203 const char* data,
204 int length) {
205 HttpConnection* http_connection = FindConnection(connection);
206 if (http_connection == NULL) {
207 LOG(WARNING) << "Unknown connection.";
208 return;
209 }
210 http_connection->ReceiveData(std::string(data, length));
211 }
212
213 void HttpServer::DidClose(net::StreamListenSocket* connection) {
214 HttpConnection* http_connection = FindConnection(connection);
215 if (http_connection == NULL) {
216 LOG(WARNING) << "Unknown connection.";
217 return;
218 }
219 delete http_connection;
220 connections_.erase(connection);
221 }
222
223 HttpConnection* HttpServer::FindConnection(
224 net::StreamListenSocket* socket) {
225 std::map<net::StreamListenSocket*, HttpConnection*>::iterator it =
226 connections_.find(socket);
227 if (it == connections_.end()) {
228 return NULL;
229 }
230 return it->second;
231 }
232
233 } // namespace test_server
234 } // namespace drive
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698