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

Side by Side Diff: net/server/http_server.cc

Issue 7540023: DevTools: no way to remote debug using ToT build as a client. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review comments addressed. Created 9 years, 4 months 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/md5.h"
10 #include "base/string_number_conversions.h"
11 #include "base/string_util.h" 9 #include "base/string_util.h"
12 #include "base/stringprintf.h" 10 #include "base/stringprintf.h"
13 #include "build/build_config.h" 11 #include "build/build_config.h"
12 #include "net/server/http_connection.h"
14 #include "net/server/http_server_request_info.h" 13 #include "net/server/http_server_request_info.h"
14 #include "net/server/web_socket.h"
15 15
16 #if defined(OS_WIN) 16 #if defined(OS_WIN)
17 #include <winsock2.h> 17 #include <winsock2.h>
18 #else 18 #else
19 #include <arpa/inet.h> 19 #include <arpa/inet.h>
20 #endif 20 #endif
21 21
22 namespace net { 22 namespace net {
23 23
24 int HttpServer::Connection::lastId_ = 0;
25
26 HttpServer::HttpServer(const std::string& host, 24 HttpServer::HttpServer(const std::string& host,
27 int port, 25 int port,
28 HttpServer::Delegate* del) 26 HttpServer::Delegate* del)
29 : delegate_(del) { 27 : delegate_(del) {
30 server_ = ListenSocket::Listen(host, port, this); 28 server_ = ListenSocket::Listen(host, port, this);
31 } 29 }
32 30
33 HttpServer::~HttpServer() { 31 HttpServer::~HttpServer() {
34 IdToConnectionMap copy = id_to_connection_; 32 IdToConnectionMap copy = id_to_connection_;
35 for (IdToConnectionMap::iterator it = copy.begin(); it != copy.end(); ++it) 33 for (IdToConnectionMap::iterator it = copy.begin(); it != copy.end(); ++it)
36 delete it->second; 34 delete it->second;
37 35
38 server_ = NULL; 36 server_ = NULL;
39 } 37 }
40 38
41 std::string GetHeaderValue( 39 void HttpServer::Send(int connection_id, const std::string& data) {
42 const HttpServerRequestInfo& request, 40 HttpConnection* connection = FindConnection(connection_id);
43 const std::string& header_name) { 41 if (connection == NULL)
44 HttpServerRequestInfo::HeadersMap::iterator it = 42 return;
45 request.headers.find(header_name); 43 connection->Send(data);
46 if (it != request.headers.end())
47 return it->second;
48 return "";
49 } 44 }
50 45
51 uint32 WebSocketKeyFingerprint(const std::string& str) { 46 void HttpServer::Send(int connection_id, const char* bytes, int len) {
52 std::string result; 47 HttpConnection* connection = FindConnection(connection_id);
53 const char* pChar = str.c_str();
54 int length = str.length();
55 int spaces = 0;
56 for (int i = 0; i < length; ++i) {
57 if (pChar[i] >= '0' && pChar[i] <= '9')
58 result.append(&pChar[i], 1);
59 else if (pChar[i] == ' ')
60 spaces++;
61 }
62 if (spaces == 0)
63 return 0;
64 int64 number = 0;
65 if (!base::StringToInt64(result, &number))
66 return 0;
67 return htonl(static_cast<uint32>(number / spaces));
68 }
69
70 void HttpServer::AcceptWebSocket(
71 int connection_id,
72 const HttpServerRequestInfo& request) {
73 Connection* connection = FindConnection(connection_id);
74 if (connection == NULL) 48 if (connection == NULL)
75 return; 49 return;
76 50
77 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); 51 connection->Send(bytes, len);
78 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2");
79
80 uint32 fp1 = WebSocketKeyFingerprint(key1);
81 uint32 fp2 = WebSocketKeyFingerprint(key2);
82
83 char data[16];
84 memcpy(data, &fp1, 4);
85 memcpy(data + 4, &fp2, 4);
86 memcpy(data + 8, &request.data[0], 8);
87
88 base::MD5Digest digest;
89 base::MD5Sum(data, 16, &digest);
90
91 std::string origin = GetHeaderValue(request, "Origin");
92 std::string host = GetHeaderValue(request, "Host");
93 std::string location = "ws://" + host + request.path;
94 connection->is_web_socket_ = true;
95 connection->socket_->Send(base::StringPrintf(
96 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
97 "Upgrade: WebSocket\r\n"
98 "Connection: Upgrade\r\n"
99 "Sec-WebSocket-Origin: %s\r\n"
100 "Sec-WebSocket-Location: %s\r\n"
101 "\r\n",
102 origin.c_str(),
103 location.c_str()));
104 connection->socket_->Send(reinterpret_cast<char*>(digest.a), 16);
105 }
106
107 void HttpServer::SendOverWebSocket(int connection_id,
108 const std::string& data) {
109 Connection* connection = FindConnection(connection_id);
110 if (connection == NULL)
111 return;
112
113 DCHECK(connection->is_web_socket_);
114 char message_start = 0;
115 char message_end = -1;
116 connection->socket_->Send(&message_start, 1);
117 connection->socket_->Send(data);
118 connection->socket_->Send(&message_end, 1);
119 }
120
121 void HttpServer::Send(int connection_id, const std::string& data) {
122 Connection* connection = FindConnection(connection_id);
123 if (connection == NULL)
124 return;
125
126 connection->socket_->Send(data);
127 }
128
129 void HttpServer::Send(int connection_id, const char* bytes, int len) {
130 Connection* connection = FindConnection(connection_id);
131 if (connection == NULL)
132 return;
133
134 connection->socket_->Send(bytes, len);
135 } 52 }
136 53
137 void HttpServer::Send200(int connection_id, 54 void HttpServer::Send200(int connection_id,
138 const std::string& data, 55 const std::string& data,
139 const std::string& content_type) { 56 const std::string& content_type) {
140 Connection* connection = FindConnection(connection_id); 57 HttpConnection* connection = FindConnection(connection_id);
141 if (connection == NULL) 58 if (connection == NULL)
142 return; 59 return;
143 60 connection->Send200(data, content_type);
144 connection->socket_->Send(base::StringPrintf(
145 "HTTP/1.1 200 OK\r\n"
146 "Content-Type:%s\r\n"
147 "Content-Length:%d\r\n"
148 "\r\n",
149 content_type.c_str(),
150 static_cast<int>(data.length())));
151 connection->socket_->Send(data);
152 } 61 }
153 62
154 void HttpServer::Send404(int connection_id) { 63 void HttpServer::Send404(int connection_id) {
155 Connection* connection = FindConnection(connection_id); 64 HttpConnection* connection = FindConnection(connection_id);
156 if (connection == NULL) 65 if (connection == NULL)
157 return; 66 return;
158 67 connection->Send404();
159 connection->socket_->Send(
160 "HTTP/1.1 404 Not Found\r\n"
161 "Content-Length: 0\r\n"
162 "\r\n");
163 } 68 }
164 69
165 void HttpServer::Send500(int connection_id, const std::string& message) { 70 void HttpServer::Send500(int connection_id, const std::string& message) {
166 Connection* connection = FindConnection(connection_id); 71 HttpConnection* connection = FindConnection(connection_id);
167 if (connection == NULL) 72 if (connection == NULL)
168 return; 73 return;
169 74 connection->Send500(message);
170 connection->socket_->Send(base::StringPrintf(
171 "HTTP/1.1 500 Internal Error\r\n"
172 "Content-Type:text/html\r\n"
173 "Content-Length:%d\r\n"
174 "\r\n"
175 "%s",
176 static_cast<int>(message.length()),
177 message.c_str()));
178 } 75 }
179 76
180 void HttpServer::Close(int connection_id) 77 void HttpServer::Close(int connection_id)
181 { 78 {
182 Connection* connection = FindConnection(connection_id); 79 HttpConnection* connection = FindConnection(connection_id);
183 if (connection == NULL) 80 if (connection == NULL)
184 return; 81 return;
185 82
186 connection->DetachSocket(); 83 connection->DetachSocket();
187 } 84 }
188 85
189 HttpServer::Connection::Connection(HttpServer* server, ListenSocket* sock)
190 : server_(server),
191 socket_(sock),
192 is_web_socket_(false) {
193 id_ = lastId_++;
194 }
195
196 HttpServer::Connection::~Connection() {
197 DetachSocket();
198 server_->delegate_->OnClose(id_);
199 }
200
201 void HttpServer::Connection::DetachSocket() {
202 socket_ = NULL;
203 }
204
205 void HttpServer::Connection::Shift(int num_bytes) {
206 recv_data_ = recv_data_.substr(num_bytes);
207 }
208
209 // 86 //
210 // HTTP Request Parser 87 // HTTP Request Parser
211 // This HTTP request parser uses a simple state machine to quickly parse 88 // This HTTP request parser uses a simple state machine to quickly parse
212 // through the headers. The parser is not 100% complete, as it is designed 89 // through the headers. The parser is not 100% complete, as it is designed
213 // for use in this simple test driver. 90 // for use in this simple test driver.
214 // 91 //
215 // Known issues: 92 // Known issues:
216 // - does not handle whitespace on first HTTP line correctly. Expects 93 // - does not handle whitespace on first HTTP line correctly. Expects
217 // a single space between the method/url and url/protocol. 94 // a single space between the method/url and url/protocol.
218 95
219 // Input character types. 96 // Input character types.
220 enum header_parse_inputs { 97 enum header_parse_inputs {
221 INPUT_SPACE, 98 INPUT_SPACE,
222 INPUT_CR, 99 INPUT_CR,
223 INPUT_LF, 100 INPUT_LF,
224 INPUT_COLON, 101 INPUT_COLON,
225 INPUT_00,
226 INPUT_FF,
227 INPUT_DEFAULT, 102 INPUT_DEFAULT,
228 MAX_INPUTS, 103 MAX_INPUTS,
229 }; 104 };
230 105
231 // Parser states. 106 // Parser states.
232 enum header_parse_states { 107 enum header_parse_states {
233 ST_METHOD, // Receiving the method 108 ST_METHOD, // Receiving the method
234 ST_URL, // Receiving the URL 109 ST_URL, // Receiving the URL
235 ST_PROTO, // Receiving the protocol 110 ST_PROTO, // Receiving the protocol
236 ST_HEADER, // Starting a Request Header 111 ST_HEADER, // Starting a Request Header
237 ST_NAME, // Receiving a request header name 112 ST_NAME, // Receiving a request header name
238 ST_SEPARATOR, // Receiving the separator between header name and value 113 ST_SEPARATOR, // Receiving the separator between header name and value
239 ST_VALUE, // Receiving a request header value 114 ST_VALUE, // Receiving a request header value
240 ST_WS_READY, // Ready to receive web socket frame
241 ST_WS_FRAME, // Receiving WebSocket frame
242 ST_WS_CLOSE, // Closing the connection WebSocket connection
243 ST_DONE, // Parsing is complete and successful 115 ST_DONE, // Parsing is complete and successful
244 ST_ERR, // Parsing encountered invalid syntax. 116 ST_ERR, // Parsing encountered invalid syntax.
245 MAX_STATES 117 MAX_STATES
246 }; 118 };
247 119
248 // State transition table 120 // State transition table
249 int parser_state[MAX_STATES][MAX_INPUTS] = { 121 int parser_state[MAX_STATES][MAX_INPUTS] = {
250 /* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_METHOD }, 122 /* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD },
251 /* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_ERR, ST_ERR, ST_URL }, 123 /* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL },
252 /* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_ERR, ST_ERR, ST_PROTO }, 124 /* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO },
253 /* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR, ST_ERR, ST_ERR }, 125 /* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR },
254 /* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_ERR, ST_ERR, ST_NAME }, 126 /* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_NAME },
255 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE }, 127 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_VALUE },
256 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_ERR, ST_ERR, ST_VALUE }, 128 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE },
257 /* WS_READY */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_WS_FR AME, ST_WS_CLOSE, ST_ERR}, 129 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE },
258 /* WS_FRAME */ { ST_WS_FRAME, ST_WS_FRAME, ST_WS_FRAME, ST_WS_FRAME, ST_ERR, ST_WS_READY, ST_WS_FRAME }, 130 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR }
259 /* WS_CLOSE */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_WS_CL OSE, ST_ERR, ST_ERR },
260 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE },
261 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR }
262 }; 131 };
263 132
264 // Convert an input character to the parser's input token. 133 // Convert an input character to the parser's input token.
265 int charToInput(char ch) { 134 int charToInput(char ch) {
266 switch(ch) { 135 switch(ch) {
267 case ' ': 136 case ' ':
268 return INPUT_SPACE; 137 return INPUT_SPACE;
269 case '\r': 138 case '\r':
270 return INPUT_CR; 139 return INPUT_CR;
271 case '\n': 140 case '\n':
272 return INPUT_LF; 141 return INPUT_LF;
273 case ':': 142 case ':':
274 return INPUT_COLON; 143 return INPUT_COLON;
275 case 0x0:
276 return INPUT_00;
277 case static_cast<char>(-1):
278 return INPUT_FF;
279 } 144 }
280 return INPUT_DEFAULT; 145 return INPUT_DEFAULT;
281 } 146 }
282 147
283 bool HttpServer::ParseHeaders(Connection* connection, 148 bool HttpServer::ParseHeaders(HttpConnection* connection,
284 HttpServerRequestInfo* info, 149 HttpServerRequestInfo* info,
285 int* ppos) { 150 size_t* ppos) {
286 int& pos = *ppos; 151 size_t& pos = *ppos;
287 int data_len = connection->recv_data_.length(); 152 size_t data_len = connection->recv_data_.length();
288 int state = connection->is_web_socket_ ? ST_WS_READY : ST_METHOD; 153 int state = ST_METHOD;
289 std::string buffer; 154 std::string buffer;
290 std::string header_name; 155 std::string header_name;
291 std::string header_value; 156 std::string header_value;
292 while (pos < data_len) { 157 while (pos < data_len) {
293 char ch = connection->recv_data_[pos++]; 158 char ch = connection->recv_data_[pos++];
294 int input = charToInput(ch); 159 int input = charToInput(ch);
295 int next_state = parser_state[state][input]; 160 int next_state = parser_state[state][input];
296 161
297 bool transition = (next_state != state); 162 bool transition = (next_state != state);
298 if (transition) { 163 if (transition) {
(...skipping 19 matching lines...) Expand all
318 case ST_VALUE: 183 case ST_VALUE:
319 header_value = buffer; 184 header_value = buffer;
320 // TODO(mbelshe): Deal better with duplicate headers 185 // TODO(mbelshe): Deal better with duplicate headers
321 DCHECK(info->headers.find(header_name) == info->headers.end()); 186 DCHECK(info->headers.find(header_name) == info->headers.end());
322 info->headers[header_name] = header_value; 187 info->headers[header_name] = header_value;
323 buffer.clear(); 188 buffer.clear();
324 break; 189 break;
325 case ST_SEPARATOR: 190 case ST_SEPARATOR:
326 buffer.append(&ch, 1); 191 buffer.append(&ch, 1);
327 break; 192 break;
328 case ST_WS_FRAME:
329 info->data = buffer;
330 buffer.clear();
331 return true;
332 break;
333 } 193 }
334 state = next_state; 194 state = next_state;
335 } else { 195 } else {
336 // Do any actions based on current state 196 // Do any actions based on current state
337 switch (state) { 197 switch (state) {
338 case ST_METHOD: 198 case ST_METHOD:
339 case ST_URL: 199 case ST_URL:
340 case ST_PROTO: 200 case ST_PROTO:
341 case ST_VALUE: 201 case ST_VALUE:
342 case ST_NAME: 202 case ST_NAME:
343 case ST_WS_FRAME:
344 buffer.append(&ch, 1); 203 buffer.append(&ch, 1);
345 break; 204 break;
346 case ST_DONE: 205 case ST_DONE:
347 DCHECK(input == INPUT_LF); 206 DCHECK(input == INPUT_LF);
348 return true; 207 return true;
349 case ST_WS_CLOSE:
350 connection->is_web_socket_ = false;
351 return false;
352 case ST_ERR: 208 case ST_ERR:
353 return false; 209 return false;
354 } 210 }
355 } 211 }
356 } 212 }
357 // No more characters, but we haven't finished parsing yet. 213 // No more characters, but we haven't finished parsing yet.
358 return false; 214 return false;
359 } 215 }
360 216
361 void HttpServer::DidAccept(ListenSocket* server, 217 void HttpServer::DidAccept(ListenSocket* server,
362 ListenSocket* socket) { 218 ListenSocket* socket) {
363 Connection* connection = new Connection(this, socket); 219 HttpConnection* connection = new HttpConnection(this, socket);
364 id_to_connection_[connection->id_] = connection; 220 id_to_connection_[connection->id()] = connection;
365 socket_to_connection_[socket] = connection; 221 socket_to_connection_[socket] = connection;
366 } 222 }
367 223
368 void HttpServer::DidRead(ListenSocket* socket, 224 void HttpServer::DidRead(ListenSocket* socket,
369 const char* data, 225 const char* data,
370 int len) { 226 int len) {
371 Connection* connection = FindConnection(socket); 227 HttpConnection* connection = FindConnection(socket);
372 DCHECK(connection != NULL); 228 DCHECK(connection != NULL);
373 if (connection == NULL) 229 if (connection == NULL)
374 return; 230 return;
375 231
376 connection->recv_data_.append(data, len); 232 connection->recv_data_.append(data, len);
377 while (connection->recv_data_.length()) { 233 while (connection->recv_data_.length()) {
378 int pos = 0; 234 if (connection->web_socket_.get()) {
235 std::string message;
236 WebSocket::ParseResult result = connection->web_socket_->Read(&message);
237 if (result == WebSocket::FRAME_INCOMPLETE)
238 break;
239
240 if (result == WebSocket::FRAME_ERROR) {
241 Close(connection->id());
242 break;
243 }
244 delegate_->OnWebSocketMessage(connection->id(), message);
245 continue;
246 }
247
379 HttpServerRequestInfo request; 248 HttpServerRequestInfo request;
249 size_t pos = 0;
380 if (!ParseHeaders(connection, &request, &pos)) 250 if (!ParseHeaders(connection, &request, &pos))
381 break; 251 break;
382 252
383 if (connection->is_web_socket_) { 253 std::string connection_header = request.GetHeaderValue("Connection");
384 delegate_->OnWebSocketMessage(connection->id_, request.data); 254 if (connection_header == "Upgrade") {
255 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection,
256 request,
257 &pos));
258
259 if (!connection->web_socket_.get()) // Not enought data was received.
260 break;
261 delegate_->OnWebSocketRequest(connection->id(), request);
385 connection->Shift(pos); 262 connection->Shift(pos);
386 continue; 263 continue;
387 } 264 }
388
389 std::string connection_header = GetHeaderValue(request, "Connection");
390 if (connection_header == "Upgrade") {
391 // Is this WebSocket and if yes, upgrade the connection.
392 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1");
393 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2");
394
395 const int websocket_handshake_body_len = 8;
396 if (pos + websocket_handshake_body_len >
397 static_cast<int>(connection->recv_data_.length())) {
398 // We haven't received websocket handshake body yet. Wait.
399 break;
400 }
401
402 if (!key1.empty() && !key2.empty()) {
403 request.data = connection->recv_data_.substr(
404 pos,
405 pos + websocket_handshake_body_len);
406 pos += websocket_handshake_body_len;
407 delegate_->OnWebSocketRequest(connection->id_, request);
408 connection->Shift(pos);
409 continue;
410 }
411 }
412 // Request body is not supported. It is always empty. 265 // Request body is not supported. It is always empty.
413 delegate_->OnHttpRequest(connection->id_, request); 266 delegate_->OnHttpRequest(connection->id(), request);
414 connection->Shift(pos); 267 connection->Shift(pos);
415 } 268 }
416 } 269 }
417 270
418 void HttpServer::DidClose(ListenSocket* socket) { 271 void HttpServer::DidClose(ListenSocket* socket) {
419 Connection* connection = FindConnection(socket); 272 HttpConnection* connection = FindConnection(socket);
420 DCHECK(connection != NULL); 273 DCHECK(connection != NULL);
421 id_to_connection_.erase(connection->id_); 274 id_to_connection_.erase(connection->id());
422 socket_to_connection_.erase(connection->socket_); 275 socket_to_connection_.erase(connection->socket_);
423 delete connection; 276 delete connection;
424 } 277 }
425 278
426 HttpServer::Connection* HttpServer::FindConnection(int connection_id) { 279 HttpConnection* HttpServer::FindConnection(int connection_id) {
427 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id); 280 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id);
428 if (it == id_to_connection_.end()) 281 if (it == id_to_connection_.end())
429 return NULL; 282 return NULL;
430 return it->second; 283 return it->second;
431 } 284 }
432 285
433 HttpServer::Connection* HttpServer::FindConnection(ListenSocket* socket) { 286 HttpConnection* HttpServer::FindConnection(ListenSocket* socket) {
434 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); 287 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket);
435 if (it == socket_to_connection_.end()) 288 if (it == socket_to_connection_.end())
436 return NULL; 289 return NULL;
437 return it->second; 290 return it->second;
438 } 291 }
439 292
293 void HttpServer::AcceptWebSocket(
294 int connection_id,
295 const HttpServerRequestInfo& request) {
296 HttpConnection* connection = FindConnection(connection_id);
297 if (connection == NULL)
298 return;
299
300 DCHECK(connection->web_socket_.get());
301 connection->web_socket_->Accept(request);
302 }
303
304 void HttpServer::SendOverWebSocket(int connection_id,
305 const std::string& data) {
306 HttpConnection* connection = FindConnection(connection_id);
307 if (connection == NULL)
308 return;
309 DCHECK(connection->web_socket_.get());
310 connection->web_socket_->Send(data);
311 }
312
440 } // namespace net 313 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698