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

Side by Side Diff: net/websockets/websocket_channel.cc

Issue 26544003: Make net::WebSocketChannel deletion safe and enable new IPCs (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Minor comment fix. Created 7 years, 2 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/websockets/websocket_channel.h" 5 #include "net/websockets/websocket_channel.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/basictypes.h" // for size_t 9 #include "base/basictypes.h" // for size_t
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
11 #include "base/safe_numerics.h" 12 #include "base/safe_numerics.h"
12 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
13 #include "net/base/big_endian.h" 14 #include "net/base/big_endian.h"
14 #include "net/base/io_buffer.h" 15 #include "net/base/io_buffer.h"
15 #include "net/base/net_log.h" 16 #include "net/base/net_log.h"
16 #include "net/websockets/websocket_errors.h" 17 #include "net/websockets/websocket_errors.h"
17 #include "net/websockets/websocket_event_interface.h" 18 #include "net/websockets/websocket_event_interface.h"
18 #include "net/websockets/websocket_frame.h" 19 #include "net/websockets/websocket_frame.h"
19 #include "net/websockets/websocket_mux.h" 20 #include "net/websockets/websocket_mux.h"
20 #include "net/websockets/websocket_stream.h" 21 #include "net/websockets/websocket_stream.h"
21 22
22 namespace net { 23 namespace net {
23 24
24 namespace { 25 namespace {
25 26
26 const int kDefaultSendQuotaLowWaterMark = 1 << 16; 27 const int kDefaultSendQuotaLowWaterMark = 1 << 16;
27 const int kDefaultSendQuotaHighWaterMark = 1 << 17; 28 const int kDefaultSendQuotaHighWaterMark = 1 << 17;
28 const size_t kWebSocketCloseCodeLength = 2; 29 const size_t kWebSocketCloseCodeLength = 2;
30 typedef WebSocketEventInterface::ChannelState ChannelState;
31 const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
32 const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;
29 33
30 } // namespace 34 } // namespace
31 35
32 // A class to encapsulate a set of frames and information about the size of 36 // A class to encapsulate a set of frames and information about the size of
33 // those frames. 37 // those frames.
34 class WebSocketChannel::SendBuffer { 38 class WebSocketChannel::SendBuffer {
35 public: 39 public:
36 SendBuffer() : total_bytes_(0) {} 40 SendBuffer() : total_bytes_(0) {}
37 41
38 // Add a WebSocketFrame to the buffer and increase total_bytes_. 42 // Add a WebSocketFrame to the buffer and increase total_bytes_.
(...skipping 19 matching lines...) Expand all
58 62
59 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the 63 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the
60 // calls on to the WebSocketChannel that created it. 64 // calls on to the WebSocketChannel that created it.
61 class WebSocketChannel::ConnectDelegate 65 class WebSocketChannel::ConnectDelegate
62 : public WebSocketStream::ConnectDelegate { 66 : public WebSocketStream::ConnectDelegate {
63 public: 67 public:
64 explicit ConnectDelegate(WebSocketChannel* creator) : creator_(creator) {} 68 explicit ConnectDelegate(WebSocketChannel* creator) : creator_(creator) {}
65 69
66 virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE { 70 virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE {
67 creator_->OnConnectSuccess(stream.Pass()); 71 creator_->OnConnectSuccess(stream.Pass());
72 // |this| may have been deleted.
68 } 73 }
69 74
70 virtual void OnFailure(uint16 websocket_error) OVERRIDE { 75 virtual void OnFailure(uint16 websocket_error) OVERRIDE {
71 creator_->OnConnectFailure(websocket_error); 76 creator_->OnConnectFailure(websocket_error);
77 // |this| has been deleted.
72 } 78 }
73 79
74 private: 80 private:
75 // A pointer to the WebSocketChannel that created this object. There is no 81 // A pointer to the WebSocketChannel that created this object. There is no
76 // danger of this pointer being stale, because deleting the WebSocketChannel 82 // danger of this pointer being stale, because deleting the WebSocketChannel
77 // cancels the connect process, deleting this object and preventing its 83 // cancels the connect process, deleting this object and preventing its
78 // callbacks from being called. 84 // callbacks from being called.
79 WebSocketChannel* const creator_; 85 WebSocketChannel* const creator_;
80 86
81 DISALLOW_COPY_AND_ASSIGN(ConnectDelegate); 87 DISALLOW_COPY_AND_ASSIGN(ConnectDelegate);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 if (InClosingState()) { 140 if (InClosingState()) {
135 VLOG(1) << "SendFrame called in state " << state_ 141 VLOG(1) << "SendFrame called in state " << state_
136 << ". This may be a bug, or a harmless race."; 142 << ". This may be a bug, or a harmless race.";
137 return; 143 return;
138 } 144 }
139 if (state_ != CONNECTED) { 145 if (state_ != CONNECTED) {
140 NOTREACHED() << "SendFrame() called in state " << state_; 146 NOTREACHED() << "SendFrame() called in state " << state_;
141 return; 147 return;
142 } 148 }
143 if (data.size() > base::checked_numeric_cast<size_t>(current_send_quota_)) { 149 if (data.size() > base::checked_numeric_cast<size_t>(current_send_quota_)) {
144 FailChannel(SEND_GOING_AWAY, 150 ChannelState unused ALLOW_UNUSED =
145 kWebSocketMuxErrorSendQuotaViolation, 151 FailChannel(SEND_GOING_AWAY,
146 "Send quota exceeded"); 152 kWebSocketMuxErrorSendQuotaViolation,
153 "Send quota exceeded");
154 // |this| is deleted here.
147 return; 155 return;
148 } 156 }
149 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) { 157 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) {
150 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code 158 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code
151 << "; misbehaving renderer? fin=" << fin 159 << "; misbehaving renderer? fin=" << fin
152 << " data.size()=" << data.size(); 160 << " data.size()=" << data.size();
153 return; 161 return;
154 } 162 }
155 current_send_quota_ -= data.size(); 163 current_send_quota_ -= data.size();
156 // TODO(ricea): If current_send_quota_ has dropped below 164 // TODO(ricea): If current_send_quota_ has dropped below
157 // send_quota_low_water_mark_, it might be good to increase the "low 165 // send_quota_low_water_mark_, it might be good to increase the "low
158 // water mark" and "high water mark", but only if the link to the WebSocket 166 // water mark" and "high water mark", but only if the link to the WebSocket
159 // server is not saturated. 167 // server is not saturated.
160 // TODO(ricea): For kOpCodeText, do UTF-8 validation? 168 // TODO(ricea): For kOpCodeText, do UTF-8 validation?
161 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size())); 169 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size()));
162 std::copy(data.begin(), data.end(), buffer->data()); 170 std::copy(data.begin(), data.end(), buffer->data());
163 SendIOBuffer(fin, op_code, buffer, data.size()); 171 ChannelState unused ALLOW_UNUSED =
172 SendIOBuffer(fin, op_code, buffer, data.size());
173 // |this| may have been deleted.
164 } 174 }
165 175
166 void WebSocketChannel::SendFlowControl(int64 quota) { 176 void WebSocketChannel::SendFlowControl(int64 quota) {
167 DCHECK_EQ(CONNECTED, state_); 177 DCHECK_EQ(CONNECTED, state_);
168 // TODO(ricea): Add interface to WebSocketStream and implement. 178 // TODO(ricea): Add interface to WebSocketStream and implement.
169 // stream_->SendFlowControl(quota); 179 // stream_->SendFlowControl(quota);
170 } 180 }
171 181
172 void WebSocketChannel::StartClosingHandshake(uint16 code, 182 void WebSocketChannel::StartClosingHandshake(uint16 code,
173 const std::string& reason) { 183 const std::string& reason) {
174 if (InClosingState()) { 184 if (InClosingState()) {
175 VLOG(1) << "StartClosingHandshake called in state " << state_ 185 VLOG(1) << "StartClosingHandshake called in state " << state_
176 << ". This may be a bug, or a harmless race."; 186 << ". This may be a bug, or a harmless race.";
177 return; 187 return;
178 } 188 }
179 if (state_ != CONNECTED) { 189 if (state_ != CONNECTED) {
180 NOTREACHED() << "StartClosingHandshake() called in state " << state_; 190 NOTREACHED() << "StartClosingHandshake() called in state " << state_;
181 return; 191 return;
182 } 192 }
183 // TODO(ricea): Validate |code|? Check that |reason| is valid UTF-8? 193 // TODO(ricea): Validate |code|
184 // TODO(ricea): There should be a timeout for the closing handshake. 194 // TODO(ricea): There should be a timeout for the closing handshake.
185 SendClose(code, reason); // Sets state_ to SEND_CLOSED 195 ChannelState unused ALLOW_UNUSED = SendClose(
196 code, IsStringUTF8(reason) ? reason : std::string()); // Sets state_ to
197 // SEND_CLOSED
198 // If |unused| is CHANNEL_DELETED, then |this| has been deleted.
186 } 199 }
187 200
188 void WebSocketChannel::SendAddChannelRequestForTesting( 201 void WebSocketChannel::SendAddChannelRequestForTesting(
189 const GURL& socket_url, 202 const GURL& socket_url,
190 const std::vector<std::string>& requested_subprotocols, 203 const std::vector<std::string>& requested_subprotocols,
191 const GURL& origin, 204 const GURL& origin,
192 const WebSocketStreamFactory& factory) { 205 const WebSocketStreamFactory& factory) {
193 SendAddChannelRequestWithFactory(socket_url, 206 SendAddChannelRequestWithFactory(
194 requested_subprotocols, 207 socket_url, requested_subprotocols, origin, factory);
195 origin,
196 factory);
197 } 208 }
198 209
199 void WebSocketChannel::SendAddChannelRequestWithFactory( 210 void WebSocketChannel::SendAddChannelRequestWithFactory(
200 const GURL& socket_url, 211 const GURL& socket_url,
201 const std::vector<std::string>& requested_subprotocols, 212 const std::vector<std::string>& requested_subprotocols,
202 const GURL& origin, 213 const GURL& origin,
203 const WebSocketStreamFactory& factory) { 214 const WebSocketStreamFactory& factory) {
204 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_); 215 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_);
205 socket_url_ = socket_url; 216 socket_url_ = socket_url;
206 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate( 217 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate(
207 new ConnectDelegate(this)); 218 new ConnectDelegate(this));
208 stream_request_ = factory.Run(socket_url_, 219 stream_request_ = factory.Run(socket_url_,
209 requested_subprotocols, 220 requested_subprotocols,
210 origin, 221 origin,
211 url_request_context_, 222 url_request_context_,
212 BoundNetLog(), 223 BoundNetLog(),
213 connect_delegate.Pass()); 224 connect_delegate.Pass());
214 state_ = CONNECTING; 225 state_ = CONNECTING;
215 } 226 }
216 227
217 void WebSocketChannel::OnConnectSuccess(scoped_ptr<WebSocketStream> stream) { 228 void WebSocketChannel::OnConnectSuccess(scoped_ptr<WebSocketStream> stream) {
218 DCHECK(stream); 229 DCHECK(stream);
219 DCHECK_EQ(CONNECTING, state_); 230 DCHECK_EQ(CONNECTING, state_);
220 stream_ = stream.Pass(); 231 stream_ = stream.Pass();
221 state_ = CONNECTED; 232 state_ = CONNECTED;
222 event_interface_->OnAddChannelResponse(false, stream_->GetSubProtocol()); 233 if (event_interface_->OnAddChannelResponse(
234 false, stream_->GetSubProtocol()) == CHANNEL_DELETED)
235 return;
223 236
224 // TODO(ricea): Get flow control information from the WebSocketStream once we 237 // TODO(ricea): Get flow control information from the WebSocketStream once we
225 // have a multiplexing WebSocketStream. 238 // have a multiplexing WebSocketStream.
226 current_send_quota_ = send_quota_high_water_mark_; 239 current_send_quota_ = send_quota_high_water_mark_;
227 event_interface_->OnFlowControl(send_quota_high_water_mark_); 240 if (event_interface_->OnFlowControl(send_quota_high_water_mark_) ==
241 CHANNEL_DELETED)
242 return;
228 243
229 // |stream_request_| is not used once the connection has succeeded. 244 // |stream_request_| is not used once the connection has succeeded.
230 stream_request_.reset(); 245 stream_request_.reset();
231 ReadFrames(); 246 ChannelState unused ALLOW_UNUSED = ReadFrames();
247 // |this| may have been deleted.
232 } 248 }
233 249
234 void WebSocketChannel::OnConnectFailure(uint16 websocket_error) { 250 void WebSocketChannel::OnConnectFailure(uint16 websocket_error) {
235 DCHECK_EQ(CONNECTING, state_); 251 DCHECK_EQ(CONNECTING, state_);
236 state_ = CLOSED; 252 state_ = CLOSED;
237 stream_request_.reset(); 253 stream_request_.reset();
238 event_interface_->OnAddChannelResponse(true, ""); 254 ChannelState unused ALLOW_UNUSED =
255 event_interface_->OnAddChannelResponse(true, "");
256 // |this| has been deleted.
239 } 257 }
240 258
241 void WebSocketChannel::WriteFrames() { 259 ChannelState WebSocketChannel::WriteFrames() {
242 int result = OK; 260 int result = OK;
243 do { 261 do {
244 // This use of base::Unretained is safe because this object owns the 262 // This use of base::Unretained is safe because this object owns the
245 // WebSocketStream and destroying it cancels all callbacks. 263 // WebSocketStream and destroying it cancels all callbacks.
246 result = stream_->WriteFrames( 264 result = stream_->WriteFrames(
247 data_being_sent_->frames(), 265 data_being_sent_->frames(),
248 base::Bind( 266 base::Bind(base::IgnoreResult(&WebSocketChannel::OnWriteDone),
249 &WebSocketChannel::OnWriteDone, base::Unretained(this), false)); 267 base::Unretained(this),
268 false));
250 if (result != ERR_IO_PENDING) { 269 if (result != ERR_IO_PENDING) {
251 OnWriteDone(true, result); 270 if (OnWriteDone(true, result) == CHANNEL_DELETED)
271 return CHANNEL_DELETED;
252 } 272 }
253 } while (result == OK && data_being_sent_); 273 } while (result == OK && data_being_sent_);
274 return CHANNEL_ALIVE;
254 } 275 }
255 276
256 void WebSocketChannel::OnWriteDone(bool synchronous, int result) { 277 ChannelState WebSocketChannel::OnWriteDone(bool synchronous, int result) {
257 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); 278 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
258 DCHECK_NE(CONNECTING, state_); 279 DCHECK_NE(CONNECTING, state_);
259 DCHECK_NE(ERR_IO_PENDING, result); 280 DCHECK_NE(ERR_IO_PENDING, result);
260 DCHECK(data_being_sent_); 281 DCHECK(data_being_sent_);
261 switch (result) { 282 switch (result) {
262 case OK: 283 case OK:
263 if (data_to_send_next_) { 284 if (data_to_send_next_) {
264 data_being_sent_ = data_to_send_next_.Pass(); 285 data_being_sent_ = data_to_send_next_.Pass();
265 if (!synchronous) { 286 if (!synchronous) {
266 WriteFrames(); 287 if (WriteFrames() == CHANNEL_DELETED)
288 return CHANNEL_DELETED;
267 } 289 }
268 } else { 290 } else {
269 data_being_sent_.reset(); 291 data_being_sent_.reset();
270 if (current_send_quota_ < send_quota_low_water_mark_) { 292 if (current_send_quota_ < send_quota_low_water_mark_) {
271 // TODO(ricea): Increase low_water_mark and high_water_mark if 293 // TODO(ricea): Increase low_water_mark and high_water_mark if
272 // throughput is high, reduce them if throughput is low. Low water 294 // throughput is high, reduce them if throughput is low. Low water
273 // mark needs to be >= the bandwidth delay product *of the IPC 295 // mark needs to be >= the bandwidth delay product *of the IPC
274 // channel*. Because factors like context-switch time, thread wake-up 296 // channel*. Because factors like context-switch time, thread wake-up
275 // time, and bus speed come into play it is complex and probably needs 297 // time, and bus speed come into play it is complex and probably needs
276 // to be determined empirically. 298 // to be determined empirically.
277 DCHECK_LE(send_quota_low_water_mark_, send_quota_high_water_mark_); 299 DCHECK_LE(send_quota_low_water_mark_, send_quota_high_water_mark_);
278 // TODO(ricea): Truncate quota by the quota specified by the remote 300 // TODO(ricea): Truncate quota by the quota specified by the remote
279 // server, if the protocol in use supports quota. 301 // server, if the protocol in use supports quota.
280 int fresh_quota = send_quota_high_water_mark_ - current_send_quota_; 302 int fresh_quota = send_quota_high_water_mark_ - current_send_quota_;
281 current_send_quota_ += fresh_quota; 303 current_send_quota_ += fresh_quota;
282 event_interface_->OnFlowControl(fresh_quota); 304 if (event_interface_->OnFlowControl(fresh_quota) == CHANNEL_DELETED)
305 return CHANNEL_DELETED;
283 } 306 }
284 } 307 }
285 return; 308 return CHANNEL_ALIVE;
286 309
287 // If a recoverable error condition existed, it would go here. 310 // If a recoverable error condition existed, it would go here.
288 311
289 default: 312 default:
290 DCHECK_LT(result, 0) 313 DCHECK_LT(result, 0)
291 << "WriteFrames() should only return OK or ERR_ codes"; 314 << "WriteFrames() should only return OK or ERR_ codes";
292 stream_->Close(); 315 stream_->Close();
293 if (state_ != CLOSED) { 316 DCHECK_NE(CLOSED, state_);
294 state_ = CLOSED; 317 state_ = CLOSED;
295 event_interface_->OnDropChannel(kWebSocketErrorAbnormalClosure, 318 return event_interface_->OnDropChannel(kWebSocketErrorAbnormalClosure,
296 "Abnormal Closure"); 319 "Abnormal Closure");
297 }
298 return;
299 } 320 }
300 } 321 }
301 322
302 void WebSocketChannel::ReadFrames() { 323 ChannelState WebSocketChannel::ReadFrames() {
303 int result = OK; 324 int result = OK;
304 do { 325 do {
305 // This use of base::Unretained is safe because this object owns the 326 // This use of base::Unretained is safe because this object owns the
306 // WebSocketStream, and any pending reads will be cancelled when it is 327 // WebSocketStream, and any pending reads will be cancelled when it is
307 // destroyed. 328 // destroyed.
308 result = stream_->ReadFrames( 329 result = stream_->ReadFrames(
309 &read_frames_, 330 &read_frames_,
310 base::Bind( 331 base::Bind(base::IgnoreResult(&WebSocketChannel::OnReadDone),
311 &WebSocketChannel::OnReadDone, base::Unretained(this), false)); 332 base::Unretained(this),
333 false));
312 if (result != ERR_IO_PENDING) { 334 if (result != ERR_IO_PENDING) {
313 OnReadDone(true, result); 335 if (OnReadDone(true, result) == CHANNEL_DELETED)
336 return CHANNEL_DELETED;
314 } 337 }
315 } while (result == OK && state_ != CLOSED); 338 DCHECK_NE(CLOSED, state_);
339 } while (result == OK);
340 return CHANNEL_ALIVE;
316 } 341 }
317 342
318 void WebSocketChannel::OnReadDone(bool synchronous, int result) { 343 ChannelState WebSocketChannel::OnReadDone(bool synchronous, int result) {
319 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); 344 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
320 DCHECK_NE(CONNECTING, state_); 345 DCHECK_NE(CONNECTING, state_);
321 DCHECK_NE(ERR_IO_PENDING, result); 346 DCHECK_NE(ERR_IO_PENDING, result);
322 switch (result) { 347 switch (result) {
323 case OK: 348 case OK:
324 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection 349 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection
325 // with no data read, not an empty response. 350 // with no data read, not an empty response.
326 DCHECK(!read_frames_.empty()) 351 DCHECK(!read_frames_.empty())
327 << "ReadFrames() returned OK, but nothing was read."; 352 << "ReadFrames() returned OK, but nothing was read.";
328 for (size_t i = 0; i < read_frames_.size(); ++i) { 353 for (size_t i = 0; i < read_frames_.size(); ++i) {
329 scoped_ptr<WebSocketFrame> frame(read_frames_[i]); 354 scoped_ptr<WebSocketFrame> frame(read_frames_[i]);
330 read_frames_[i] = NULL; 355 read_frames_[i] = NULL;
331 ProcessFrame(frame.Pass()); 356 if (ProcessFrame(frame.Pass()) == CHANNEL_DELETED)
357 return CHANNEL_DELETED;
332 } 358 }
333 read_frames_.clear(); 359 read_frames_.clear();
334 // There should always be a call to ReadFrames pending. 360 // There should always be a call to ReadFrames pending.
335 // TODO(ricea): Unless we are out of quota. 361 // TODO(ricea): Unless we are out of quota.
336 if (!synchronous && state_ != CLOSED) { 362 DCHECK_NE(CLOSED, state_);
337 ReadFrames(); 363 if (!synchronous) {
364 if (ReadFrames() == CHANNEL_DELETED)
365 return CHANNEL_DELETED;
338 } 366 }
339 return; 367 return CHANNEL_ALIVE;
340 368
341 case ERR_WS_PROTOCOL_ERROR: 369 case ERR_WS_PROTOCOL_ERROR:
342 FailChannel(SEND_REAL_ERROR, 370 return FailChannel(SEND_REAL_ERROR,
343 kWebSocketErrorProtocolError, 371 kWebSocketErrorProtocolError,
344 "WebSocket Protocol Error"); 372 "WebSocket Protocol Error");
345 return;
346 373
347 default: 374 default:
348 DCHECK_LT(result, 0) 375 DCHECK_LT(result, 0)
349 << "ReadFrames() should only return OK or ERR_ codes"; 376 << "ReadFrames() should only return OK or ERR_ codes";
350 stream_->Close(); 377 stream_->Close();
351 if (state_ != CLOSED) { 378 DCHECK_NE(CLOSED, state_);
352 state_ = CLOSED; 379 state_ = CLOSED;
353 uint16 code = kWebSocketErrorAbnormalClosure; 380 uint16 code = kWebSocketErrorAbnormalClosure;
354 std::string reason = "Abnormal Closure"; 381 std::string reason = "Abnormal Closure";
355 if (closing_code_ != 0) { 382 if (closing_code_ != 0) {
356 code = closing_code_; 383 code = closing_code_;
357 reason = closing_reason_; 384 reason = closing_reason_;
358 }
359 event_interface_->OnDropChannel(code, reason);
360 } 385 }
361 return; 386 return event_interface_->OnDropChannel(code, reason);
362 } 387 }
363 } 388 }
364 389
365 void WebSocketChannel::ProcessFrame(scoped_ptr<WebSocketFrame> frame) { 390 ChannelState WebSocketChannel::ProcessFrame(scoped_ptr<WebSocketFrame> frame) {
366 if (frame->header.masked) { 391 if (frame->header.masked) {
367 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a 392 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a
368 // masked frame." 393 // masked frame."
369 FailChannel(SEND_REAL_ERROR, 394 return FailChannel(SEND_REAL_ERROR,
370 kWebSocketErrorProtocolError, 395 kWebSocketErrorProtocolError,
371 "Masked frame from server"); 396 "Masked frame from server");
372 return;
373 } 397 }
374 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode; 398 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode;
375 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) && 399 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) &&
376 !frame->header.final) { 400 !frame->header.final) {
377 FailChannel(SEND_REAL_ERROR, 401 return FailChannel(SEND_REAL_ERROR,
378 kWebSocketErrorProtocolError, 402 kWebSocketErrorProtocolError,
379 "Control message with FIN bit unset received"); 403 "Control message with FIN bit unset received");
380 return;
381 } 404 }
382 405
383 // Respond to the frame appropriately to its type. 406 // Respond to the frame appropriately to its type.
384 HandleFrame( 407 return HandleFrame(
385 opcode, frame->header.final, frame->data, frame->header.payload_length); 408 opcode, frame->header.final, frame->data, frame->header.payload_length);
386 } 409 }
387 410
388 void WebSocketChannel::HandleFrame(const WebSocketFrameHeader::OpCode opcode, 411 ChannelState WebSocketChannel::HandleFrame(
389 bool final, 412 const WebSocketFrameHeader::OpCode opcode,
390 const scoped_refptr<IOBuffer>& data_buffer, 413 bool final,
391 size_t size) { 414 const scoped_refptr<IOBuffer>& data_buffer,
415 size_t size) {
392 DCHECK_NE(RECV_CLOSED, state_) 416 DCHECK_NE(RECV_CLOSED, state_)
393 << "HandleFrame() does not support being called re-entrantly from within " 417 << "HandleFrame() does not support being called re-entrantly from within "
394 "SendClose()"; 418 "SendClose()";
395 if (state_ == CLOSED || state_ == CLOSE_WAIT) { 419 DCHECK_NE(CLOSED, state_);
396 DVLOG_IF(1, state_ == CLOSED) << "A frame was received while in the CLOSED " 420 if (state_ == CLOSE_WAIT) {
397 "state. This is possible after a channel "
398 "failed, but should be very rare.";
399 std::string frame_name; 421 std::string frame_name;
400 switch (opcode) { 422 switch (opcode) {
401 case WebSocketFrameHeader::kOpCodeText: // fall-thru 423 case WebSocketFrameHeader::kOpCodeText: // fall-thru
402 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru 424 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru
403 case WebSocketFrameHeader::kOpCodeContinuation: 425 case WebSocketFrameHeader::kOpCodeContinuation:
404 frame_name = "Data frame"; 426 frame_name = "Data frame";
405 break; 427 break;
406 428
407 case WebSocketFrameHeader::kOpCodePing: 429 case WebSocketFrameHeader::kOpCodePing:
408 frame_name = "Ping"; 430 frame_name = "Ping";
409 break; 431 break;
410 432
411 case WebSocketFrameHeader::kOpCodePong: 433 case WebSocketFrameHeader::kOpCodePong:
412 frame_name = "Pong"; 434 frame_name = "Pong";
413 break; 435 break;
414 436
415 case WebSocketFrameHeader::kOpCodeClose: 437 case WebSocketFrameHeader::kOpCodeClose:
416 frame_name = "Close"; 438 frame_name = "Close";
417 break; 439 break;
418 440
419 default: 441 default:
420 frame_name = "Unknown frame type"; 442 frame_name = "Unknown frame type";
421 break; 443 break;
422 } 444 }
423 // SEND_REAL_ERROR makes no difference here, as FailChannel() won't send 445 // SEND_REAL_ERROR makes no difference here, as FailChannel() won't send
424 // another Close frame. 446 // another Close frame.
425 FailChannel(SEND_REAL_ERROR, 447 return FailChannel(SEND_REAL_ERROR,
426 kWebSocketErrorProtocolError, 448 kWebSocketErrorProtocolError,
427 frame_name + " received after close"); 449 frame_name + " received after close");
428 return;
429 } 450 }
430 switch (opcode) { 451 switch (opcode) {
431 case WebSocketFrameHeader::kOpCodeText: // fall-thru 452 case WebSocketFrameHeader::kOpCodeText: // fall-thru
432 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru 453 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru
433 case WebSocketFrameHeader::kOpCodeContinuation: 454 case WebSocketFrameHeader::kOpCodeContinuation:
434 if (state_ == CONNECTED) { 455 if (state_ == CONNECTED) {
435 // TODO(ricea): Need to fail the connection if UTF-8 is invalid 456 // TODO(ricea): Need to fail the connection if UTF-8 is invalid
436 // post-reassembly. Requires a streaming UTF-8 validator. 457 // post-reassembly. Requires a streaming UTF-8 validator.
437 // TODO(ricea): Can this copy be eliminated? 458 // TODO(ricea): Can this copy be eliminated?
438 const char* const data_begin = data_buffer->data(); 459 const char* const data_begin = data_buffer->data();
439 const char* const data_end = data_begin + size; 460 const char* const data_end = data_begin + size;
440 const std::vector<char> data(data_begin, data_end); 461 const std::vector<char> data(data_begin, data_end);
441 // TODO(ricea): Handle the case when ReadFrames returns far 462 // TODO(ricea): Handle the case when ReadFrames returns far
442 // more data at once than should be sent in a single IPC. This needs to 463 // more data at once than should be sent in a single IPC. This needs to
443 // be handled carefully, as an overloaded IO thread is one possible 464 // be handled carefully, as an overloaded IO thread is one possible
444 // cause of receiving very large chunks. 465 // cause of receiving very large chunks.
445 466
446 // Sends the received frame to the renderer process. 467 // Sends the received frame to the renderer process.
447 event_interface_->OnDataFrame(final, opcode, data); 468 if (event_interface_->OnDataFrame(final, opcode, data) ==
469 CHANNEL_DELETED)
470 return CHANNEL_DELETED;
tyoshino (SeeGerritForStatus) 2013/10/15 07:22:15 just return the result of OnDataFrame.
Adam Rice 2013/10/15 08:31:42 Done.
448 } else { 471 } else {
449 VLOG(3) << "Ignored data packet received in state " << state_; 472 VLOG(3) << "Ignored data packet received in state " << state_;
450 } 473 }
451 return; 474 return CHANNEL_ALIVE;
tyoshino (SeeGerritForStatus) 2013/10/15 07:22:15 move this to L472
Adam Rice 2013/10/15 08:31:42 Done.
452 475
453 case WebSocketFrameHeader::kOpCodePing: 476 case WebSocketFrameHeader::kOpCodePing:
454 VLOG(1) << "Got Ping of size " << size; 477 VLOG(1) << "Got Ping of size " << size;
455 if (state_ == CONNECTED) { 478 if (state_ == CONNECTED) {
456 SendIOBuffer( 479 if (SendIOBuffer(
457 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); 480 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size) ==
481 CHANNEL_DELETED)
482 return CHANNEL_DELETED;
458 } else { 483 } else {
459 VLOG(3) << "Ignored ping in state " << state_; 484 VLOG(3) << "Ignored ping in state " << state_;
460 } 485 }
461 return; 486 return CHANNEL_ALIVE;
462 487
463 case WebSocketFrameHeader::kOpCodePong: 488 case WebSocketFrameHeader::kOpCodePong:
464 VLOG(1) << "Got Pong of size " << size; 489 VLOG(1) << "Got Pong of size " << size;
465 // There is no need to do anything with pong messages. 490 // There is no need to do anything with pong messages.
466 return; 491 return CHANNEL_ALIVE;
467 492
468 case WebSocketFrameHeader::kOpCodeClose: { 493 case WebSocketFrameHeader::kOpCodeClose: {
469 uint16 code = kWebSocketNormalClosure; 494 uint16 code = kWebSocketNormalClosure;
470 std::string reason; 495 std::string reason;
471 ParseClose(data_buffer, size, &code, &reason); 496 ParseClose(data_buffer, size, &code, &reason);
472 // TODO(ricea): Find a way to safely log the message from the close 497 // TODO(ricea): Find a way to safely log the message from the close
473 // message (escape control codes and so on). 498 // message (escape control codes and so on).
474 VLOG(1) << "Got Close with code " << code; 499 VLOG(1) << "Got Close with code " << code;
475 switch (state_) { 500 switch (state_) {
476 case CONNECTED: 501 case CONNECTED:
477 state_ = RECV_CLOSED; 502 state_ = RECV_CLOSED;
478 SendClose(code, reason); // Sets state_ to CLOSE_WAIT 503 if (SendClose(code, reason) // Sets state_ to CLOSE_WAIT
479 event_interface_->OnClosingHandshake(); 504 == CHANNEL_DELETED)
505 return CHANNEL_DELETED;
506 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED)
507 return CHANNEL_DELETED;
480 closing_code_ = code; 508 closing_code_ = code;
481 closing_reason_ = reason; 509 closing_reason_ = reason;
482 break; 510 break;
483 511
484 case SEND_CLOSED: 512 case SEND_CLOSED:
485 state_ = CLOSE_WAIT; 513 state_ = CLOSE_WAIT;
486 // From RFC6455 section 7.1.5: "Each endpoint 514 // From RFC6455 section 7.1.5: "Each endpoint
487 // will see the status code sent by the other end as _The WebSocket 515 // will see the status code sent by the other end as _The WebSocket
488 // Connection Close Code_." 516 // Connection Close Code_."
489 closing_code_ = code; 517 closing_code_ = code;
490 closing_reason_ = reason; 518 closing_reason_ = reason;
491 break; 519 break;
492 520
493 default: 521 default:
494 LOG(DFATAL) << "Got Close in unexpected state " << state_; 522 LOG(DFATAL) << "Got Close in unexpected state " << state_;
495 break; 523 break;
496 } 524 }
497 return; 525 return CHANNEL_ALIVE;
498 } 526 }
499 527
500 default: 528 default:
501 FailChannel( 529 return FailChannel(
502 SEND_REAL_ERROR, kWebSocketErrorProtocolError, "Unknown opcode"); 530 SEND_REAL_ERROR, kWebSocketErrorProtocolError, "Unknown opcode");
503 return;
504 } 531 }
505 } 532 }
506 533
507 void WebSocketChannel::SendIOBuffer(bool fin, 534 ChannelState WebSocketChannel::SendIOBuffer(
508 WebSocketFrameHeader::OpCode op_code, 535 bool fin,
509 const scoped_refptr<IOBuffer>& buffer, 536 WebSocketFrameHeader::OpCode op_code,
510 size_t size) { 537 const scoped_refptr<IOBuffer>& buffer,
538 size_t size) {
511 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); 539 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
512 DCHECK(stream_); 540 DCHECK(stream_);
513 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); 541 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code));
514 WebSocketFrameHeader& header = frame->header; 542 WebSocketFrameHeader& header = frame->header;
515 header.final = fin; 543 header.final = fin;
516 header.masked = true; 544 header.masked = true;
517 header.payload_length = size; 545 header.payload_length = size;
518 frame->data = buffer; 546 frame->data = buffer;
519 if (data_being_sent_) { 547 if (data_being_sent_) {
520 // Either the link to the WebSocket server is saturated, or several messages 548 // Either the link to the WebSocket server is saturated, or several messages
521 // are being sent in a batch. 549 // are being sent in a batch.
522 // TODO(ricea): Keep some statistics to work out the situation and adjust 550 // TODO(ricea): Keep some statistics to work out the situation and adjust
523 // quota appropriately. 551 // quota appropriately.
524 if (!data_to_send_next_) 552 if (!data_to_send_next_)
525 data_to_send_next_.reset(new SendBuffer); 553 data_to_send_next_.reset(new SendBuffer);
526 data_to_send_next_->AddFrame(frame.Pass()); 554 data_to_send_next_->AddFrame(frame.Pass());
tyoshino (SeeGerritForStatus) 2013/10/15 07:22:15 return CHANNEL_ALIVE here, and return WriteFrame
Adam Rice 2013/10/15 08:31:42 Done.
527 } else { 555 } else {
528 data_being_sent_.reset(new SendBuffer); 556 data_being_sent_.reset(new SendBuffer);
529 data_being_sent_->AddFrame(frame.Pass()); 557 data_being_sent_->AddFrame(frame.Pass());
530 WriteFrames(); 558 if (WriteFrames() == CHANNEL_DELETED)
559 return CHANNEL_DELETED;
531 } 560 }
561 return CHANNEL_ALIVE;
532 } 562 }
533 563
534 void WebSocketChannel::FailChannel(ExposeError expose, 564 ChannelState WebSocketChannel::FailChannel(ExposeError expose,
535 uint16 code, 565 uint16 code,
536 const std::string& reason) { 566 const std::string& reason) {
537 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); 567 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
538 DCHECK_NE(CONNECTING, state_); 568 DCHECK_NE(CONNECTING, state_);
569 DCHECK_NE(CLOSED, state_);
539 // TODO(ricea): Logging. 570 // TODO(ricea): Logging.
540 State old_state = state_;
541 if (state_ == CONNECTED) { 571 if (state_ == CONNECTED) {
542 uint16 send_code = kWebSocketErrorGoingAway; 572 uint16 send_code = kWebSocketErrorGoingAway;
543 std::string send_reason = "Internal Error"; 573 std::string send_reason = "Internal Error";
544 if (expose == SEND_REAL_ERROR) { 574 if (expose == SEND_REAL_ERROR) {
545 send_code = code; 575 send_code = code;
546 send_reason = reason; 576 send_reason = reason;
547 } 577 }
548 SendClose(send_code, send_reason); // Sets state_ to SEND_CLOSED 578 if (SendClose(send_code, send_reason) // Sets state_ to SEND_CLOSED
579 == CHANNEL_DELETED)
580 return CHANNEL_DELETED;
549 } 581 }
550 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser 582 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser
551 // should close the connection itself without waiting for the closing 583 // should close the connection itself without waiting for the closing
552 // handshake. 584 // handshake.
553 stream_->Close(); 585 stream_->Close();
554 state_ = CLOSED; 586 state_ = CLOSED;
555 587
556 if (old_state != CLOSED) { 588 return event_interface_->OnDropChannel(code, reason);
557 event_interface_->OnDropChannel(code, reason);
558 }
559 } 589 }
560 590
561 void WebSocketChannel::SendClose(uint16 code, const std::string& reason) { 591 ChannelState WebSocketChannel::SendClose(uint16 code,
592 const std::string& reason) {
562 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); 593 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
563 // TODO(ricea): Ensure reason.length() <= 123 594 // TODO(ricea): Ensure reason.length() <= 123
564 scoped_refptr<IOBuffer> body; 595 scoped_refptr<IOBuffer> body;
565 size_t size = 0; 596 size_t size = 0;
566 if (code == kWebSocketErrorNoStatusReceived) { 597 if (code == kWebSocketErrorNoStatusReceived) {
567 // Special case: translate kWebSocketErrorNoStatusReceived into a Close 598 // Special case: translate kWebSocketErrorNoStatusReceived into a Close
568 // frame with no payload. 599 // frame with no payload.
569 body = new IOBuffer(0); 600 body = new IOBuffer(0);
570 } else { 601 } else {
571 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); 602 const size_t payload_length = kWebSocketCloseCodeLength + reason.length();
572 body = new IOBuffer(payload_length); 603 body = new IOBuffer(payload_length);
573 size = payload_length; 604 size = payload_length;
574 WriteBigEndian(body->data(), code); 605 WriteBigEndian(body->data(), code);
575 COMPILE_ASSERT(sizeof(code) == kWebSocketCloseCodeLength, 606 COMPILE_ASSERT(sizeof(code) == kWebSocketCloseCodeLength,
576 they_should_both_be_two); 607 they_should_both_be_two);
577 std::copy( 608 std::copy(
578 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); 609 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
579 } 610 }
580 SendIOBuffer(true, WebSocketFrameHeader::kOpCodeClose, body, size); 611 if (SendIOBuffer(true, WebSocketFrameHeader::kOpCodeClose, body, size) ==
612 CHANNEL_DELETED)
613 return CHANNEL_DELETED;
581 state_ = (state_ == CONNECTED) ? SEND_CLOSED : CLOSE_WAIT; 614 state_ = (state_ == CONNECTED) ? SEND_CLOSED : CLOSE_WAIT;
615 return CHANNEL_ALIVE;
582 } 616 }
583 617
584 void WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, 618 void WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer,
585 size_t size, 619 size_t size,
586 uint16* code, 620 uint16* code,
587 std::string* reason) { 621 std::string* reason) {
588 const char* data = buffer->data(); 622 const char* data = buffer->data();
589 reason->clear(); 623 reason->clear();
590 if (size < kWebSocketCloseCodeLength) { 624 if (size < kWebSocketCloseCodeLength) {
591 *code = kWebSocketErrorNoStatusReceived; 625 *code = kWebSocketErrorNoStatusReceived;
(...skipping 12 matching lines...) Expand all
604 if (unchecked_code >= static_cast<uint16>(kWebSocketNormalClosure) && 638 if (unchecked_code >= static_cast<uint16>(kWebSocketNormalClosure) &&
605 unchecked_code <= 639 unchecked_code <=
606 static_cast<uint16>(kWebSocketErrorPrivateReservedMax)) { 640 static_cast<uint16>(kWebSocketErrorPrivateReservedMax)) {
607 *code = unchecked_code; 641 *code = unchecked_code;
608 } else { 642 } else {
609 VLOG(1) << "Close frame contained code outside of the valid range: " 643 VLOG(1) << "Close frame contained code outside of the valid range: "
610 << unchecked_code; 644 << unchecked_code;
611 *code = kWebSocketErrorAbnormalClosure; 645 *code = kWebSocketErrorAbnormalClosure;
612 } 646 }
613 std::string text(data + kWebSocketCloseCodeLength, data + size); 647 std::string text(data + kWebSocketCloseCodeLength, data + size);
614 // TODO(ricea): Is this check strict enough? In particular, check the 648 // IsStringUTF8() blocks surrogate pairs and non-characters, so it is strictly
615 // "Security Considerations" from RFC3629. 649 // stronger than required by RFC3629.
616 if (IsStringUTF8(text)) { 650 if (IsStringUTF8(text)) {
617 reason->swap(text); 651 reason->swap(text);
618 } 652 }
619 } 653 }
620 654
621 } // namespace net 655 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698