OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "net/server/http_server.h" | 5 #include "net/server/http_server.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
13 #include "base/sys_byteorder.h" | 13 #include "base/sys_byteorder.h" |
14 #include "build/build_config.h" | 14 #include "build/build_config.h" |
15 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
16 #include "net/server/http_connection.h" | 16 #include "net/server/http_connection.h" |
17 #include "net/server/http_server_request_info.h" | 17 #include "net/server/http_server_request_info.h" |
18 #include "net/server/http_server_response_info.h" | 18 #include "net/server/http_server_response_info.h" |
19 #include "net/server/web_socket.h" | 19 #include "net/server/web_socket.h" |
20 #include "net/socket/server_socket.h" | 20 #include "net/socket/tcp_listen_socket.h" |
21 #include "net/socket/stream_socket.h" | |
22 #include "net/socket/tcp_server_socket.h" | |
23 | 21 |
24 namespace net { | 22 namespace net { |
25 | 23 |
26 HttpServer::HttpServer(scoped_ptr<ServerSocket> server_socket, | 24 HttpServer::HttpServer(const StreamListenSocketFactory& factory, |
27 HttpServer::Delegate* delegate) | 25 HttpServer::Delegate* delegate) |
28 : server_socket_(server_socket.Pass()), | 26 : delegate_(delegate), |
29 delegate_(delegate), | 27 server_(factory.CreateAndListen(this)) { |
30 last_id_(0), | |
31 weak_ptr_factory_(this) { | |
32 DCHECK(server_socket_); | |
33 DoAcceptLoop(); | |
34 } | |
35 | |
36 HttpServer::~HttpServer() { | |
37 STLDeleteContainerPairSecondPointers( | |
38 id_to_connection_.begin(), id_to_connection_.end()); | |
39 } | 28 } |
40 | 29 |
41 void HttpServer::AcceptWebSocket( | 30 void HttpServer::AcceptWebSocket( |
42 int connection_id, | 31 int connection_id, |
43 const HttpServerRequestInfo& request) { | 32 const HttpServerRequestInfo& request) { |
44 HttpConnection* connection = FindConnection(connection_id); | 33 HttpConnection* connection = FindConnection(connection_id); |
45 if (connection == NULL) | 34 if (connection == NULL) |
46 return; | 35 return; |
47 DCHECK(connection->web_socket()); | 36 |
48 connection->web_socket()->Accept(request); | 37 DCHECK(connection->web_socket_.get()); |
| 38 connection->web_socket_->Accept(request); |
49 } | 39 } |
50 | 40 |
51 void HttpServer::SendOverWebSocket(int connection_id, | 41 void HttpServer::SendOverWebSocket(int connection_id, |
52 const std::string& data) { | 42 const std::string& data) { |
53 HttpConnection* connection = FindConnection(connection_id); | 43 HttpConnection* connection = FindConnection(connection_id); |
54 if (connection == NULL) | 44 if (connection == NULL) |
55 return; | 45 return; |
56 DCHECK(connection->web_socket()); | 46 DCHECK(connection->web_socket_.get()); |
57 connection->web_socket()->Send(data); | 47 connection->web_socket_->Send(data); |
58 } | 48 } |
59 | 49 |
60 void HttpServer::SendRaw(int connection_id, const std::string& data) { | 50 void HttpServer::SendRaw(int connection_id, const std::string& data) { |
61 HttpConnection* connection = FindConnection(connection_id); | 51 HttpConnection* connection = FindConnection(connection_id); |
62 if (connection == NULL) | 52 if (connection == NULL) |
63 return; | 53 return; |
64 | 54 connection->Send(data); |
65 bool writing_in_progress = !connection->write_buf()->IsEmpty(); | |
66 if (connection->write_buf()->Append(data) && !writing_in_progress) | |
67 DoWriteLoop(connection); | |
68 } | 55 } |
69 | 56 |
70 void HttpServer::SendResponse(int connection_id, | 57 void HttpServer::SendResponse(int connection_id, |
71 const HttpServerResponseInfo& response) { | 58 const HttpServerResponseInfo& response) { |
72 SendRaw(connection_id, response.Serialize()); | 59 HttpConnection* connection = FindConnection(connection_id); |
| 60 if (connection == NULL) |
| 61 return; |
| 62 connection->Send(response); |
73 } | 63 } |
74 | 64 |
75 void HttpServer::Send(int connection_id, | 65 void HttpServer::Send(int connection_id, |
76 HttpStatusCode status_code, | 66 HttpStatusCode status_code, |
77 const std::string& data, | 67 const std::string& data, |
78 const std::string& content_type) { | 68 const std::string& content_type) { |
79 HttpServerResponseInfo response(status_code); | 69 HttpServerResponseInfo response(status_code); |
80 response.SetContentHeaders(data.size(), content_type); | 70 response.SetBody(data, content_type); |
81 SendResponse(connection_id, response); | 71 SendResponse(connection_id, response); |
82 SendRaw(connection_id, data); | |
83 } | 72 } |
84 | 73 |
85 void HttpServer::Send200(int connection_id, | 74 void HttpServer::Send200(int connection_id, |
86 const std::string& data, | 75 const std::string& data, |
87 const std::string& content_type) { | 76 const std::string& content_type) { |
88 Send(connection_id, HTTP_OK, data, content_type); | 77 Send(connection_id, HTTP_OK, data, content_type); |
89 } | 78 } |
90 | 79 |
91 void HttpServer::Send404(int connection_id) { | 80 void HttpServer::Send404(int connection_id) { |
92 SendResponse(connection_id, HttpServerResponseInfo::CreateFor404()); | 81 SendResponse(connection_id, HttpServerResponseInfo::CreateFor404()); |
93 } | 82 } |
94 | 83 |
95 void HttpServer::Send500(int connection_id, const std::string& message) { | 84 void HttpServer::Send500(int connection_id, const std::string& message) { |
96 SendResponse(connection_id, HttpServerResponseInfo::CreateFor500(message)); | 85 SendResponse(connection_id, HttpServerResponseInfo::CreateFor500(message)); |
97 } | 86 } |
98 | 87 |
99 void HttpServer::Close(int connection_id) { | 88 void HttpServer::Close(int connection_id) { |
100 HttpConnection* connection = FindConnection(connection_id); | 89 HttpConnection* connection = FindConnection(connection_id); |
101 if (connection == NULL) | 90 if (connection == NULL) |
102 return; | 91 return; |
103 | 92 |
104 id_to_connection_.erase(connection_id); | 93 // Initiating close from server-side does not lead to the DidClose call. |
105 delegate_->OnClose(connection_id); | 94 // Do it manually here. |
106 | 95 DidClose(connection->socket_.get()); |
107 // The call stack might have callbacks which still have the pointer of | |
108 // connection. Instead of referencing connection with ID all the time, | |
109 // destroys the connection in next run loop to make sure any pending | |
110 // callbacks in the call stack return. | |
111 base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, connection); | |
112 } | 96 } |
113 | 97 |
114 int HttpServer::GetLocalAddress(IPEndPoint* address) { | 98 int HttpServer::GetLocalAddress(IPEndPoint* address) { |
115 return server_socket_->GetLocalAddress(address); | 99 if (!server_) |
| 100 return ERR_SOCKET_NOT_CONNECTED; |
| 101 return server_->GetLocalAddress(address); |
116 } | 102 } |
117 | 103 |
118 void HttpServer::SetReceiveBufferSize(int connection_id, int32 size) { | 104 void HttpServer::DidAccept(StreamListenSocket* server, |
119 HttpConnection* connection = FindConnection(connection_id); | 105 scoped_ptr<StreamListenSocket> socket) { |
120 DCHECK(connection); | 106 HttpConnection* connection = new HttpConnection(this, socket.Pass()); |
121 connection->read_buf()->set_max_buffer_size(size); | 107 id_to_connection_[connection->id()] = connection; |
| 108 // TODO(szym): Fix socket access. Make HttpConnection the Delegate. |
| 109 socket_to_connection_[connection->socket_.get()] = connection; |
122 } | 110 } |
123 | 111 |
124 void HttpServer::SetSendBufferSize(int connection_id, int32 size) { | 112 void HttpServer::DidRead(StreamListenSocket* socket, |
125 HttpConnection* connection = FindConnection(connection_id); | 113 const char* data, |
126 DCHECK(connection); | 114 int len) { |
127 connection->write_buf()->set_max_buffer_size(size); | 115 HttpConnection* connection = FindConnection(socket); |
128 } | 116 DCHECK(connection != NULL); |
129 | 117 if (connection == NULL) |
130 void HttpServer::DoAcceptLoop() { | |
131 int rv; | |
132 do { | |
133 rv = server_socket_->Accept(&accepted_socket_, | |
134 base::Bind(&HttpServer::OnAcceptCompleted, | |
135 weak_ptr_factory_.GetWeakPtr())); | |
136 if (rv == ERR_IO_PENDING) | |
137 return; | |
138 rv = HandleAcceptResult(rv); | |
139 } while (rv == OK); | |
140 } | |
141 | |
142 void HttpServer::OnAcceptCompleted(int rv) { | |
143 if (HandleAcceptResult(rv) == OK) | |
144 DoAcceptLoop(); | |
145 } | |
146 | |
147 int HttpServer::HandleAcceptResult(int rv) { | |
148 if (rv < 0) { | |
149 LOG(ERROR) << "Accept error: rv=" << rv; | |
150 return rv; | |
151 } | |
152 | |
153 HttpConnection* connection = | |
154 new HttpConnection(++last_id_, accepted_socket_.Pass()); | |
155 id_to_connection_[connection->id()] = connection; | |
156 DoReadLoop(connection); | |
157 return OK; | |
158 } | |
159 | |
160 void HttpServer::DoReadLoop(HttpConnection* connection) { | |
161 int rv; | |
162 do { | |
163 HttpConnection::ReadIOBuffer* read_buf = connection->read_buf(); | |
164 // Increases read buffer size if necessary. | |
165 if (read_buf->RemainingCapacity() == 0 && !read_buf->IncreaseCapacity()) { | |
166 Close(connection->id()); | |
167 return; | |
168 } | |
169 | |
170 rv = connection->socket()->Read( | |
171 read_buf, | |
172 read_buf->RemainingCapacity(), | |
173 base::Bind(&HttpServer::OnReadCompleted, | |
174 weak_ptr_factory_.GetWeakPtr(), connection->id())); | |
175 if (rv == ERR_IO_PENDING) | |
176 return; | |
177 rv = HandleReadResult(connection, rv); | |
178 } while (rv == OK); | |
179 } | |
180 | |
181 void HttpServer::OnReadCompleted(int connection_id, int rv) { | |
182 HttpConnection* connection = FindConnection(connection_id); | |
183 if (!connection) // It might be closed right before by write error. | |
184 return; | 118 return; |
185 | 119 |
186 if (HandleReadResult(connection, rv) == OK) | 120 connection->recv_data_.append(data, len); |
187 DoReadLoop(connection); | 121 while (connection->recv_data_.length()) { |
188 } | 122 if (connection->web_socket_.get()) { |
189 | |
190 int HttpServer::HandleReadResult(HttpConnection* connection, int rv) { | |
191 if (rv <= 0) { | |
192 Close(connection->id()); | |
193 return rv == 0 ? ERR_CONNECTION_CLOSED : rv; | |
194 } | |
195 | |
196 HttpConnection::ReadIOBuffer* read_buf = connection->read_buf(); | |
197 read_buf->DidRead(rv); | |
198 | |
199 // Handles http requests or websocket messages. | |
200 while (read_buf->GetSize() > 0) { | |
201 if (connection->web_socket()) { | |
202 std::string message; | 123 std::string message; |
203 WebSocket::ParseResult result = connection->web_socket()->Read(&message); | 124 WebSocket::ParseResult result = connection->web_socket_->Read(&message); |
204 if (result == WebSocket::FRAME_INCOMPLETE) | 125 if (result == WebSocket::FRAME_INCOMPLETE) |
205 break; | 126 break; |
206 | 127 |
207 if (result == WebSocket::FRAME_CLOSE || | 128 if (result == WebSocket::FRAME_CLOSE || |
208 result == WebSocket::FRAME_ERROR) { | 129 result == WebSocket::FRAME_ERROR) { |
209 Close(connection->id()); | 130 Close(connection->id()); |
210 return ERR_CONNECTION_CLOSED; | 131 break; |
211 } | 132 } |
212 delegate_->OnWebSocketMessage(connection->id(), message); | 133 delegate_->OnWebSocketMessage(connection->id(), message); |
213 if (HasClosedConnection(connection)) | |
214 return ERR_CONNECTION_CLOSED; | |
215 continue; | 134 continue; |
216 } | 135 } |
217 | 136 |
218 HttpServerRequestInfo request; | 137 HttpServerRequestInfo request; |
219 size_t pos = 0; | 138 size_t pos = 0; |
220 if (!ParseHeaders(read_buf->StartOfBuffer(), read_buf->GetSize(), | 139 if (!ParseHeaders(connection, &request, &pos)) |
221 &request, &pos)) { | |
222 break; | 140 break; |
223 } | |
224 | 141 |
225 // Sets peer address if exists. | 142 // Sets peer address if exists. |
226 connection->socket()->GetPeerAddress(&request.peer); | 143 socket->GetPeerAddress(&request.peer); |
227 | 144 |
228 if (request.HasHeaderValue("connection", "upgrade")) { | 145 if (request.HasHeaderValue("connection", "upgrade")) { |
229 scoped_ptr<WebSocket> websocket( | 146 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection, |
230 WebSocket::CreateWebSocket(this, connection, request, &pos)); | 147 request, |
231 if (!websocket) // Not enough data was received. | 148 &pos)); |
| 149 |
| 150 if (!connection->web_socket_.get()) // Not enough data was received. |
232 break; | 151 break; |
233 connection->SetWebSocket(websocket.Pass()); | |
234 read_buf->DidConsume(pos); | |
235 delegate_->OnWebSocketRequest(connection->id(), request); | 152 delegate_->OnWebSocketRequest(connection->id(), request); |
236 if (HasClosedConnection(connection)) | 153 connection->Shift(pos); |
237 return ERR_CONNECTION_CLOSED; | |
238 continue; | 154 continue; |
239 } | 155 } |
240 | 156 |
241 const char kContentLength[] = "content-length"; | 157 const char kContentLength[] = "content-length"; |
242 if (request.headers.count(kContentLength) > 0) { | 158 if (request.headers.count(kContentLength)) { |
243 size_t content_length = 0; | 159 size_t content_length = 0; |
244 const size_t kMaxBodySize = 100 << 20; | 160 const size_t kMaxBodySize = 100 << 20; |
245 if (!base::StringToSizeT(request.GetHeaderValue(kContentLength), | 161 if (!base::StringToSizeT(request.GetHeaderValue(kContentLength), |
246 &content_length) || | 162 &content_length) || |
247 content_length > kMaxBodySize) { | 163 content_length > kMaxBodySize) { |
248 SendResponse(connection->id(), | 164 connection->Send(HttpServerResponseInfo::CreateFor500( |
249 HttpServerResponseInfo::CreateFor500( | 165 "request content-length too big or unknown: " + |
250 "request content-length too big or unknown: " + | 166 request.GetHeaderValue(kContentLength))); |
251 request.GetHeaderValue(kContentLength))); | 167 DidClose(socket); |
252 Close(connection->id()); | 168 break; |
253 return ERR_CONNECTION_CLOSED; | |
254 } | 169 } |
255 | 170 |
256 if (read_buf->GetSize() - pos < content_length) | 171 if (connection->recv_data_.length() - pos < content_length) |
257 break; // Not enough data was received yet. | 172 break; // Not enough data was received yet. |
258 request.data.assign(read_buf->StartOfBuffer() + pos, content_length); | 173 request.data = connection->recv_data_.substr(pos, content_length); |
259 pos += content_length; | 174 pos += content_length; |
260 } | 175 } |
261 | 176 |
262 read_buf->DidConsume(pos); | |
263 delegate_->OnHttpRequest(connection->id(), request); | 177 delegate_->OnHttpRequest(connection->id(), request); |
264 if (HasClosedConnection(connection)) | 178 connection->Shift(pos); |
265 return ERR_CONNECTION_CLOSED; | |
266 } | |
267 | |
268 return OK; | |
269 } | |
270 | |
271 void HttpServer::DoWriteLoop(HttpConnection* connection) { | |
272 int rv = OK; | |
273 HttpConnection::QueuedWriteIOBuffer* write_buf = connection->write_buf(); | |
274 while (rv == OK && write_buf->GetSizeToWrite() > 0) { | |
275 rv = connection->socket()->Write( | |
276 write_buf, | |
277 write_buf->GetSizeToWrite(), | |
278 base::Bind(&HttpServer::OnWriteCompleted, | |
279 weak_ptr_factory_.GetWeakPtr(), connection->id())); | |
280 if (rv == ERR_IO_PENDING || rv == OK) | |
281 return; | |
282 rv = HandleWriteResult(connection, rv); | |
283 } | 179 } |
284 } | 180 } |
285 | 181 |
286 void HttpServer::OnWriteCompleted(int connection_id, int rv) { | 182 void HttpServer::DidClose(StreamListenSocket* socket) { |
287 HttpConnection* connection = FindConnection(connection_id); | 183 HttpConnection* connection = FindConnection(socket); |
288 if (!connection) // It might be closed right before by read error. | 184 DCHECK(connection != NULL); |
289 return; | 185 id_to_connection_.erase(connection->id()); |
290 | 186 socket_to_connection_.erase(connection->socket_.get()); |
291 if (HandleWriteResult(connection, rv) == OK) | 187 delete connection; |
292 DoWriteLoop(connection); | |
293 } | 188 } |
294 | 189 |
295 int HttpServer::HandleWriteResult(HttpConnection* connection, int rv) { | 190 HttpServer::~HttpServer() { |
296 if (rv < 0) { | 191 STLDeleteContainerPairSecondPointers( |
297 Close(connection->id()); | 192 id_to_connection_.begin(), id_to_connection_.end()); |
298 return rv; | |
299 } | |
300 | |
301 connection->write_buf()->DidConsume(rv); | |
302 return OK; | |
303 } | 193 } |
304 | 194 |
305 namespace { | |
306 | |
307 // | 195 // |
308 // HTTP Request Parser | 196 // HTTP Request Parser |
309 // This HTTP request parser uses a simple state machine to quickly parse | 197 // This HTTP request parser uses a simple state machine to quickly parse |
310 // through the headers. The parser is not 100% complete, as it is designed | 198 // through the headers. The parser is not 100% complete, as it is designed |
311 // for use in this simple test driver. | 199 // for use in this simple test driver. |
312 // | 200 // |
313 // Known issues: | 201 // Known issues: |
314 // - does not handle whitespace on first HTTP line correctly. Expects | 202 // - does not handle whitespace on first HTTP line correctly. Expects |
315 // a single space between the method/url and url/protocol. | 203 // a single space between the method/url and url/protocol. |
316 | 204 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 case '\r': | 248 case '\r': |
361 return INPUT_CR; | 249 return INPUT_CR; |
362 case '\n': | 250 case '\n': |
363 return INPUT_LF; | 251 return INPUT_LF; |
364 case ':': | 252 case ':': |
365 return INPUT_COLON; | 253 return INPUT_COLON; |
366 } | 254 } |
367 return INPUT_DEFAULT; | 255 return INPUT_DEFAULT; |
368 } | 256 } |
369 | 257 |
370 } // namespace | 258 bool HttpServer::ParseHeaders(HttpConnection* connection, |
371 | |
372 bool HttpServer::ParseHeaders(const char* data, | |
373 size_t data_len, | |
374 HttpServerRequestInfo* info, | 259 HttpServerRequestInfo* info, |
375 size_t* ppos) { | 260 size_t* ppos) { |
376 size_t& pos = *ppos; | 261 size_t& pos = *ppos; |
| 262 size_t data_len = connection->recv_data_.length(); |
377 int state = ST_METHOD; | 263 int state = ST_METHOD; |
378 std::string buffer; | 264 std::string buffer; |
379 std::string header_name; | 265 std::string header_name; |
380 std::string header_value; | 266 std::string header_value; |
381 while (pos < data_len) { | 267 while (pos < data_len) { |
382 char ch = data[pos++]; | 268 char ch = connection->recv_data_[pos++]; |
383 int input = charToInput(ch); | 269 int input = charToInput(ch); |
384 int next_state = parser_state[state][input]; | 270 int next_state = parser_state[state][input]; |
385 | 271 |
386 bool transition = (next_state != state); | 272 bool transition = (next_state != state); |
387 HttpServerRequestInfo::HeadersMap::iterator it; | 273 HttpServerRequestInfo::HeadersMap::iterator it; |
388 if (transition) { | 274 if (transition) { |
389 // Do any actions based on state transitions. | 275 // Do any actions based on state transitions. |
390 switch (state) { | 276 switch (state) { |
391 case ST_METHOD: | 277 case ST_METHOD: |
392 info->method = buffer; | 278 info->method = buffer; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 return false; | 330 return false; |
445 } | 331 } |
446 | 332 |
447 HttpConnection* HttpServer::FindConnection(int connection_id) { | 333 HttpConnection* HttpServer::FindConnection(int connection_id) { |
448 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id); | 334 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id); |
449 if (it == id_to_connection_.end()) | 335 if (it == id_to_connection_.end()) |
450 return NULL; | 336 return NULL; |
451 return it->second; | 337 return it->second; |
452 } | 338 } |
453 | 339 |
454 // This is called after any delegate callbacks are called to check if Close() | 340 HttpConnection* HttpServer::FindConnection(StreamListenSocket* socket) { |
455 // has been called during callback processing. Using the pointer of connection, | 341 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); |
456 // |connection| is safe here because Close() deletes the connection in next run | 342 if (it == socket_to_connection_.end()) |
457 // loop. | 343 return NULL; |
458 bool HttpServer::HasClosedConnection(HttpConnection* connection) { | 344 return it->second; |
459 return FindConnection(connection->id()) != connection; | |
460 } | 345 } |
461 | 346 |
462 } // namespace net | 347 } // namespace net |
OLD | NEW |